Merge "Do not let KitchenSink crash if VHAL is denied by SELinux" into rvc-dev
diff --git a/car-lib/src/android/car/ICarOccupantZone.aidl b/car-lib/src/android/car/ICarOccupantZone.aidl
index 904bc84..09335a7 100644
--- a/car-lib/src/android/car/ICarOccupantZone.aidl
+++ b/car-lib/src/android/car/ICarOccupantZone.aidl
@@ -30,7 +30,6 @@
     int getDisplayType(in int displayId);
     int getUserForOccupant(in int occupantZoneId);
     int getOccupantZoneIdForUserId(in int userId);
-    void setAudioZoneIdsForOccupantZoneIds(in int[] audioZoneIds, in int[] occupantZoneIds);
     void registerCallback(in ICarOccupantZoneCallback callback);
     void unregisterCallback(in ICarOccupantZoneCallback callback);
 }
diff --git a/car-lib/src/android/car/trust/CarTrustAgentEnrollmentManager.java b/car-lib/src/android/car/trust/CarTrustAgentEnrollmentManager.java
index 5087c17..c4e1989 100644
--- a/car-lib/src/android/car/trust/CarTrustAgentEnrollmentManager.java
+++ b/car-lib/src/android/car/trust/CarTrustAgentEnrollmentManager.java
@@ -67,7 +67,8 @@
  *
  * @hide
  *
- * @deprecated Enrollment of a trusted device is no longer a supported feature.
+ * @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
diff --git a/car-lib/src/android/car/trust/ICarTrustAgentBleCallback.aidl b/car-lib/src/android/car/trust/ICarTrustAgentBleCallback.aidl
index 7305542..0678db8 100644
--- a/car-lib/src/android/car/trust/ICarTrustAgentBleCallback.aidl
+++ b/car-lib/src/android/car/trust/ICarTrustAgentBleCallback.aidl
@@ -22,7 +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.
+ * @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 08c2680..485b77e 100644
--- a/car-lib/src/android/car/trust/ICarTrustAgentEnrollment.aidl
+++ b/car-lib/src/android/car/trust/ICarTrustAgentEnrollment.aidl
@@ -26,7 +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.
+ * @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 c8c3d65..b151958 100644
--- a/car-lib/src/android/car/trust/ICarTrustAgentEnrollmentCallback.aidl
+++ b/car-lib/src/android/car/trust/ICarTrustAgentEnrollmentCallback.aidl
@@ -22,7 +22,8 @@
  * Callback interface for state changes during Trusted device enrollment.
  *
  * @hide
- * @deprecated Enrolling a trusted device is no longer a supported feature.
+ * @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.java b/car-lib/src/android/car/trust/TrustedDeviceInfo.java
index b216874..1f44a83 100644
--- a/car-lib/src/android/car/trust/TrustedDeviceInfo.java
+++ b/car-lib/src/android/car/trust/TrustedDeviceInfo.java
@@ -28,7 +28,8 @@
  * Contains basic info of a trusted device.
  *
  * @hide
- * @deprecated Adding a trusted device is no longer a supported feature.
+ * @deprecated Adding a trusted device is no longer a supported feature and these APIs will be
+ * removed in the next Android release.
  */
 @Deprecated
 @SystemApi
diff --git a/evs/manager/1.1/Android.bp b/evs/manager/1.1/Android.bp
index 41ccce7..4a62715 100644
--- a/evs/manager/1.1/Android.bp
+++ b/evs/manager/1.1/Android.bp
@@ -63,4 +63,12 @@
     include_dirs: [
         "system/core/libsync",
     ],
+
+    product_variables: {
+        debuggable: {
+            cflags: [
+                "-DEVS_ALLOW_AID_ROOT",
+            ]
+        }
+    }
 }
diff --git a/evs/manager/1.1/Enumerator.cpp b/evs/manager/1.1/Enumerator.cpp
index 5c368cf..90d0570 100644
--- a/evs/manager/1.1/Enumerator.cpp
+++ b/evs/manager/1.1/Enumerator.cpp
@@ -42,10 +42,15 @@
 
 bool Enumerator::checkPermission() {
     hardware::IPCThreadState *ipc = hardware::IPCThreadState::self();
-    if (AID_AUTOMOTIVE_EVS != ipc->getCallingUid() &&
-        AID_ROOT != ipc->getCallingUid()) {
-
-        ALOGE("EVS access denied?: pid = %d, uid = %d", ipc->getCallingPid(), ipc->getCallingUid());
+    const auto userId = ipc->getCallingUid() / AID_USER_OFFSET;
+    const auto appId = ipc->getCallingUid() % AID_USER_OFFSET;
+#ifdef EVS_ALLOW_AID_ROOT
+    if (AID_AUTOMOTIVE_EVS != appId && AID_ROOT != appId && AID_SYSTEM != appId) {
+#else
+    if (AID_AUTOMOTIVE_EVS != appId && AID_SYSTEM != appId) {
+#endif
+        ALOGE("EVS access denied?: pid = %d, userId = %d, appId = %d",
+              ipc->getCallingPid(), userId, appId);
         return false;
     }
 
diff --git a/evs/sampleDriver/EvsEnumerator.cpp b/evs/sampleDriver/EvsEnumerator.cpp
index 113d669..055bc61 100644
--- a/evs/sampleDriver/EvsEnumerator.cpp
+++ b/evs/sampleDriver/EvsEnumerator.cpp
@@ -328,8 +328,10 @@
         closeDisplay(pActiveDisplay);
     }
 
-    // Create a new display interface and return it
-    pActiveDisplay = new EvsGlDisplay();
+    // Create a new display interface and return it.  Please note that this
+    // implementation uses whichever display unordered_map::begin() returns.
+    pActiveDisplay = new EvsGlDisplay(sDisplayProxy,
+                                      sDisplayPortList.begin()->second);
     sActiveDisplay = pActiveDisplay;
 
     ALOGD("Returning new EvsGlDisplay object %p", pActiveDisplay.get());
diff --git a/evs/sampleDriver/EvsGlDisplay.cpp b/evs/sampleDriver/EvsGlDisplay.cpp
index 48522df..b21d5ed 100644
--- a/evs/sampleDriver/EvsGlDisplay.cpp
+++ b/evs/sampleDriver/EvsGlDisplay.cpp
@@ -32,10 +32,6 @@
 
 static bool sDebugFirstFrameDisplayed = false;
 
-EvsGlDisplay::EvsGlDisplay() {
-    EvsGlDisplay(nullptr, 0);
-}
-
 
 EvsGlDisplay::EvsGlDisplay(sp<IAutomotiveDisplayProxyService> pDisplayProxy, uint64_t displayId)
     : mDisplayProxy(pDisplayProxy),
diff --git a/evs/sampleDriver/EvsGlDisplay.h b/evs/sampleDriver/EvsGlDisplay.h
index 3e411f9..af6dd72 100644
--- a/evs/sampleDriver/EvsGlDisplay.h
+++ b/evs/sampleDriver/EvsGlDisplay.h
@@ -53,7 +53,6 @@
     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;
 
diff --git a/evs/support_library/StreamHandler.cpp b/evs/support_library/StreamHandler.cpp
index 5b962cc..483f855 100644
--- a/evs/support_library/StreamHandler.cpp
+++ b/evs/support_library/StreamHandler.cpp
@@ -37,7 +37,9 @@
 using ::std::unique_lock;
 
 StreamHandler::StreamHandler(android::sp <IEvsCamera> pCamera) :
-    mCamera(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.
@@ -174,8 +176,11 @@
             // If analyze callback is not null and the analyze thread is
             // available, copy the frame and run the analyze callback in
             // analyze thread.
-            if (mAnalyzeCallback != nullptr && !mAnalyzerRunning) {
-                copyAndAnalyzeFrame(mOriginalBuffers[mReadyBuffer]);
+            {
+                std::shared_lock<std::shared_mutex> analyzerLock(mAnalyzerLock);
+                if (mAnalyzeCallback != nullptr && !mAnalyzerRunning) {
+                    copyAndAnalyzeFrame(mOriginalBuffers[mReadyBuffer]);
+                }
             }
         }
     }
@@ -209,20 +214,29 @@
 void StreamHandler::attachAnalyzeCallback(BaseAnalyzeCallback* callback) {
     ALOGD("StreamHandler::attachAnalyzeCallback");
 
-    lock_guard<mutex> lock(mLock);
-
     if (mAnalyzeCallback != nullptr) {
         ALOGW("Ignored! There should only be one analyze callcack");
         return;
     }
-    mAnalyzeCallback = callback;
+
+    {
+        lock_guard<std::shared_mutex> lock(mAnalyzerLock);
+        mAnalyzeCallback = callback;
+    }
 }
 
 void StreamHandler::detachAnalyzeCallback() {
     ALOGD("StreamHandler::detachAnalyzeCallback");
-    lock_guard<mutex> lock(mLock);
 
-    mAnalyzeCallback = nullptr;
+    // Join a running analyzer thread
+    if (mAnalyzeThread.joinable()) {
+        mAnalyzeThread.join();
+    }
+
+    {
+        lock_guard<std::shared_mutex> lock(mAnalyzerLock);
+        mAnalyzeCallback = nullptr;
+    }
 }
 
 bool isSameFormat(const BufferDesc& input, const BufferDesc& output) {
@@ -453,12 +467,15 @@
     mAnalyzeThread = std::thread([this, analyzeFrame]() {
         ALOGD("StreamHandler: Analyze Thread starts");
 
-        this->mAnalyzeCallback->analyze(analyzeFrame);
-        android::GraphicBufferMapper::get().unlock(this->mAnalyzeBuffer.memHandle);
+        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;
+
         ALOGD("StreamHandler: Analyze Thread ends");
     });
-    mAnalyzeThread.detach();
 
     return true;
 }
diff --git a/evs/support_library/StreamHandler.h b/evs/support_library/StreamHandler.h
index 4899809..b962cb8 100644
--- a/evs/support_library/StreamHandler.h
+++ b/evs/support_library/StreamHandler.h
@@ -19,6 +19,7 @@
 
 #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>
@@ -148,13 +149,14 @@
     int                         mReadyBuffer = -1;  // Index of the newest available buffer
 
     BufferDesc                  mProcessedBuffers[2];
-    BufferDesc                  mAnalyzeBuffer;
+    BufferDesc                  mAnalyzeBuffer GUARDED_BY(mAnalyzerLock);
 
     BaseRenderCallback*         mRenderCallback = nullptr;
 
-    BaseAnalyzeCallback*        mAnalyzeCallback = nullptr;
-    bool                        mAnalyzerRunning = false;
+    BaseAnalyzeCallback*        mAnalyzeCallback GUARDED_BY(mAnalyzerLock);
+    bool                        mAnalyzerRunning GUARDED_BY(mAnalyzerLock);
     std::thread                 mAnalyzeThread;
+    std::shared_mutex           mAnalyzerLock;
 };
 
 }  // namespace support
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/src/com/android/car/CarOccupantZoneService.java b/service/src/com/android/car/CarOccupantZoneService.java
index 9fd84fb..dae1667 100644
--- a/service/src/com/android/car/CarOccupantZoneService.java
+++ b/service/src/com/android/car/CarOccupantZoneService.java
@@ -39,13 +39,13 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 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.util.Preconditions;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -61,6 +61,8 @@
 public final class CarOccupantZoneService extends ICarOccupantZone.Stub
         implements CarServiceBase {
 
+    private static final int INVALID_OCCUPANT_ZONE_ID = -1;
+
     private final Object mLock = new Object();
     private final Context mContext;
     private final DisplayManager mDisplayManager;
@@ -98,7 +100,7 @@
 
     /** key: audio zone id */
     @GuardedBy("mLock")
-    private final HashMap<Integer, Integer> mAudioZoneConfig = new HashMap<>();
+    private final SparseIntArray mAudioZoneIdToOccupantZoneIdMapping = new SparseIntArray();
 
     @VisibleForTesting
     static class DisplayInfo {
@@ -314,7 +316,7 @@
         synchronized (mLock) {
             mOccupantsConfig.clear();
             mDisplayConfigs.clear();
-            mAudioZoneConfig.clear();
+            mAudioZoneIdToOccupantZoneIdMapping.clear();
             mActiveOccupantConfigs.clear();
         }
     }
@@ -340,9 +342,9 @@
     /** Return cloned mAudioConfigs for testing */
     @VisibleForTesting
     @NonNull
-    HashMap<Integer, Integer> getAudioConfigs() {
+    SparseIntArray getAudioConfigs() {
         synchronized (mLock) {
-            return (HashMap<Integer, Integer>) mAudioZoneConfig.clone();
+            return mAudioZoneIdToOccupantZoneIdMapping.clone();
         }
     }
 
@@ -369,10 +371,11 @@
                 writer.println(" port=" + Integer.toHexString(entry.getKey())
                         + " config=" + entry.getValue().toString());
             }
-            writer.println("**mAudioZoneConfigs**");
-            for (Map.Entry<Integer, Integer> entry : mAudioZoneConfig.entrySet()) {
-                writer.println(" audioZoneId=" + Integer.toHexString(entry.getKey())
-                        + " zoneId=" + entry.getValue());
+            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()) {
@@ -445,9 +448,10 @@
     }
 
     private int getAudioZoneIdForOccupantLocked(int occupantZoneId) {
-        for (Map.Entry<Integer, Integer> entry : mAudioZoneConfig.entrySet()) {
-            if (occupantZoneId == entry.getValue()) {
-                return entry.getKey();
+        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;
@@ -457,8 +461,9 @@
     public CarOccupantZoneManager.OccupantZoneInfo getOccupantForAudioZoneId(int audioZoneId) {
         enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
         synchronized (mLock) {
-            Integer occupantZoneId = mAudioZoneConfig.get(audioZoneId);
-            if (occupantZoneId == null) {
+            int occupantZoneId = mAudioZoneIdToOccupantZoneIdMapping.get(audioZoneId,
+                    INVALID_OCCUPANT_ZONE_ID);
+            if (occupantZoneId == INVALID_OCCUPANT_ZONE_ID) {
                 return null;
             }
             // To support headless zones return the occupant configuration.
@@ -521,19 +526,23 @@
         }
     }
 
-    @Override
-    public void setAudioZoneIdsForOccupantZoneIds(@NonNull int[] audioZoneIds,
-            @NonNull int[] occupantZoneIds) {
-        Objects.requireNonNull(audioZoneIds, "audioZoneIds can not be null");
-        Objects.requireNonNull(audioZoneIds, "occupantZoneIds can not be null");
-        Preconditions.checkArgument(audioZoneIds.length == occupantZoneIds.length,
-                "audioZoneIds and occupantZoneIds must have the same size.");
-        boolean activeConfigChange = false;
+    /**
+     * 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(occupantZoneIds);
-            mAudioZoneConfig.clear();
-            for (int i = 0; i < audioZoneIds.length; i++) {
-                mAudioZoneConfig.put(audioZoneIds[i], occupantZoneIds[i]);
+            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();
@@ -541,10 +550,12 @@
         sendConfigChangeEvent(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_AUDIO);
     }
 
-    private void validateOccupantZoneIdsLocked(int[] occupantZoneIds) {
-        for (int i = 0; i < occupantZoneIds.length; i++) {
-            if (!mOccupantsConfig.containsKey(occupantZoneIds[i])) {
-                throw new IllegalArgumentException("occupantZoneId " + occupantZoneIds[i]
+    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.");
             }
         }
@@ -813,8 +824,9 @@
     }
 
     private void handleAudioZoneChangesLocked() {
-        for (Map.Entry<Integer, Integer> entry: mAudioZoneConfig.entrySet()) {
-            int occupantZoneId = entry.getValue();
+        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) {
@@ -822,7 +834,7 @@
                 continue;
             }
             // Found an active configuration, add audio to it.
-            occupantConfig.audioZoneId = entry.getKey();
+            occupantConfig.audioZoneId = audioZoneId;
         }
     }
 
diff --git a/service/src/com/android/car/ICarImpl.java b/service/src/com/android/car/ICarImpl.java
index 1923d9a..b8adbf1 100644
--- a/service/src/com/android/car/ICarImpl.java
+++ b/service/src/com/android/car/ICarImpl.java
@@ -260,6 +260,7 @@
         CarLocalServices.addService(PerUserCarServiceHelper.class, mPerUserCarServiceHelper);
         CarLocalServices.addService(FixedActivityService.class, mFixedActivityService);
         CarLocalServices.addService(VmsNewBrokerService.class, mVmsBrokerService);
+        CarLocalServices.addService(CarOccupantZoneService.class, mCarOccupantZoneService);
 
         // Be careful with order. Service depending on other service should be inited later.
         List<CarServiceBase> allServices = new ArrayList<>();
@@ -356,7 +357,7 @@
         mCarUserService.onSwitchUser(userId);
     }
 
-    // TODO(b/146207078): this method is currently used just for metrics logging purposes, but we
+    // TODO(b/145689885): this method is currently used just for metrics logging purposes, but we
     // should fold the other too (onSwitchUser() and setUserLockStatus()) onto it.
     @Override
     public void onUserLifecycleEvent(int eventType, long timestampMs, int fromUserId,
@@ -1264,7 +1265,7 @@
                     + "), timeout=" + timeout);
 
             UserHalService userHal = mHal.getUserHal();
-            // TODO(b/146207078): use UserHalHelper to populate it with current users
+            // TODO(b/150413515): use UserHalHelper to populate it with current users
             UsersInfo usersInfo = new UsersInfo();
             CountDownLatch latch = new CountDownLatch(1);
 
diff --git a/service/src/com/android/car/audio/CarAudioContext.java b/service/src/com/android/car/audio/CarAudioContext.java
index fd5eda6..206f890 100644
--- a/service/src/com/android/car/audio/CarAudioContext.java
+++ b/service/src/com/android/car/audio/CarAudioContext.java
@@ -81,6 +81,22 @@
      *     .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,
@@ -90,9 +106,30 @@
             CALL,
             ALARM,
             NOTIFICATION,
-            SYSTEM_SOUND
+            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 {
@@ -144,6 +181,26 @@
                         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
@@ -184,28 +241,11 @@
     }
 
     static String toString(@AudioContext int audioContext) {
-        switch (audioContext) {
-            case INVALID:
-                return "INVALID";
-            case MUSIC:
-                return "MUSIC";
-            case NAVIGATION:
-                return "NAVIGATION";
-            case VOICE_COMMAND:
-                return "VOICE_COMMAND";
-            case CALL_RING:
-                return "CALL_RING";
-            case CALL:
-                return "CALL";
-            case ALARM:
-                return "ALARM";
-            case NOTIFICATION:
-                return "NOTIFICATION";
-            case SYSTEM_SOUND:
-                return "SYSTEM_SOUND";
-            default:
-                return "0x" + Integer.toHexString(audioContext);
+        String name = CONTEXT_NAMES.get(audioContext);
+        if (name != null) {
+            return name;
         }
+        return "Unsupported Context 0x" + Integer.toHexString(audioContext);
     }
 
     @IntDef({
@@ -218,6 +258,10 @@
             ALARM,
             NOTIFICATION,
             SYSTEM_SOUND,
+            EMERGENCY,
+            SAFETY,
+            VEHICLE_STATUS,
+            ANNOUNCEMENT
     })
     @Retention(RetentionPolicy.SOURCE)
     @interface AudioContext {
diff --git a/service/src/com/android/car/audio/CarAudioDynamicRouting.java b/service/src/com/android/car/audio/CarAudioDynamicRouting.java
index 661f1f1..ea61542 100644
--- a/service/src/com/android/car/audio/CarAudioDynamicRouting.java
+++ b/service/src/com/android/car/audio/CarAudioDynamicRouting.java
@@ -16,6 +16,7 @@
 package com.android.car.audio;
 
 import android.media.AudioAttributes;
+import android.media.AudioAttributes.AttributeUsage;
 import android.media.AudioFormat;
 import android.media.AudioManager;
 import android.media.audiopolicy.AudioMix;
@@ -31,9 +32,6 @@
  * Builds dynamic audio routing in a car from audio zone configuration.
  */
 /* package */ class CarAudioDynamicRouting {
-
-    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[] {
@@ -82,8 +80,8 @@
                 hasContext = true;
                 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);
                 }
                 if (Log.isLoggable(CarLog.TAG_AUDIO, Log.DEBUG)) {
@@ -106,4 +104,14 @@
             }
         }
     }
+
+    private AudioAttributes buildAttributesWithUsage(@AttributeUsage int usage) {
+        AudioAttributes.Builder attributesBuilder = new AudioAttributes.Builder();
+        if (AudioAttributes.isSystemUsage(usage)) {
+            attributesBuilder.setSystemUsage(usage);
+        } else {
+            attributesBuilder.setUsage(usage);
+        }
+        return attributesBuilder.build();
+    }
 }
diff --git a/service/src/com/android/car/audio/CarAudioFocus.java b/service/src/com/android/car/audio/CarAudioFocus.java
index f4e85a1..0bdc452 100644
--- a/service/src/com/android/car/audio/CarAudioFocus.java
+++ b/service/src/com/android/car/audio/CarAudioFocus.java
@@ -69,7 +69,7 @@
     // 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(AudioPolicy parentPolicy) {
-        mAudioPolicy     = parentPolicy;
+        mAudioPolicy = parentPolicy;
     }
 
 
@@ -117,10 +117,8 @@
         final boolean allowDucking =
                 (afi.getGainRequest() == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
 
-
-        // Convert from audio attributes "usage" to HAL level "context"
         final int requestedContext = CarAudioContext.getContextForUsage(
-                afi.getAttributes().getUsage());
+                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.
diff --git a/service/src/com/android/car/audio/CarAudioService.java b/service/src/com/android/car/audio/CarAudioService.java
index c6c98d8..b0c80a1 100644
--- a/service/src/com/android/car/audio/CarAudioService.java
+++ b/service/src/com/android/car/audio/CarAudioService.java
@@ -15,11 +15,6 @@
  */
 package com.android.car.audio;
 
-import static android.media.AudioAttributes.USAGE_ANNOUNCEMENT;
-import static android.media.AudioAttributes.USAGE_EMERGENCY;
-import static android.media.AudioAttributes.USAGE_SAFETY;
-import static android.media.AudioAttributes.USAGE_VEHICLE_STATUS;
-
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.car.Car;
@@ -36,6 +31,7 @@
 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;
@@ -55,13 +51,16 @@
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.SparseIntArray;
 import android.view.DisplayAddress;
 import android.view.KeyEvent;
 
 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.user.CarUserService;
 import com.android.internal.util.Preconditions;
 
@@ -94,8 +93,9 @@
     // 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";
+    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.
@@ -106,10 +106,11 @@
     };
 
     private static final @AttributeSystemUsage int[] SYSTEM_USAGES = new int[] {
-            USAGE_EMERGENCY,
-            USAGE_SAFETY,
-            USAGE_VEHICLE_STATUS,
-            USAGE_ANNOUNCEMENT
+            AudioAttributes.USAGE_CALL_ASSISTANT,
+            AudioAttributes.USAGE_EMERGENCY,
+            AudioAttributes.USAGE_SAFETY,
+            AudioAttributes.USAGE_VEHICLE_STATUS,
+            AudioAttributes.USAGE_ANNOUNCEMENT
     };
 
     private final Object mImplLock = new Object();
@@ -123,6 +124,8 @@
 
     private final CarUserService.UserCallback  mReceiver = new CarAudioServiceUserCallback();
 
+    private CarOccupantZoneService mOccupantZoneService;
+
     private final AudioPolicy.AudioPolicyVolumeCallback mAudioPolicyVolumeCallback =
             new AudioPolicy.AudioPolicyVolumeCallback() {
         @Override
@@ -192,6 +195,7 @@
     private AudioPolicy mAudioPolicy;
     private CarZonesAudioFocus mFocusHandler;
     private String mCarAudioConfigurationPath;
+    private SparseIntArray mAudioZoneIdToOccupantZoneIdMapping;
     private CarAudioZone[] mCarAudioZones;
     private final CarVolumeCallbackHandler mCarVolumeCallbackHandler;
 
@@ -219,6 +223,7 @@
     public void init() {
         synchronized (mImplLock) {
             CarLocalServices.getService(CarUserService.class).addUserCallback(mReceiver);
+            mOccupantZoneService = CarLocalServices.getService(CarOccupantZoneService.class);
             if (mUseDynamicRouting) {
                 setupDynamicRouting();
             } else {
@@ -423,6 +428,8 @@
         try (InputStream inputStream = new FileInputStream(mCarAudioConfigurationPath)) {
             CarAudioZonesHelper zonesHelper = new CarAudioZonesHelper(mContext, inputStream,
                     carAudioDeviceInfos, inputDevices);
+            mAudioZoneIdToOccupantZoneIdMapping =
+                    zonesHelper.getCarAudioZoneIdToOccupantZoneIdMapping();
             return zonesHelper.loadAudioZones();
         } catch (IOException | XmlPullParserException e) {
             throw new RuntimeException("Failed to parse audio zone configuration", e);
@@ -495,6 +502,12 @@
         if (r != AudioManager.SUCCESS) {
             throw new RuntimeException("registerAudioPolicy failed " + r);
         }
+
+        setupOccupantZoneInfo();
+    }
+
+    private void setupOccupantZoneInfo() {
+        mOccupantZoneService.setAudioZoneIdsForOccupantZoneIds(mAudioZoneIdToOccupantZoneIdMapping);
     }
 
     /**
@@ -740,7 +753,7 @@
             Set<Integer> contexts =
                     Arrays.stream(group.getContexts()).boxed().collect(Collectors.toSet());
             final List<Integer> usages = new ArrayList<>();
-            for (@CarAudioContext.AudioContext int context : contexts) {
+            for (@AudioContext int context : contexts) {
                 int[] usagesForContext = CarAudioContext.getUsagesForContext(context);
                 for (@AudioAttributes.AttributeUsage int usage : usagesForContext) {
                     usages.add(usage);
@@ -1016,10 +1029,10 @@
                     .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();
+                return playbacks.get(playbacks.size() - 1).getAudioAttributes().getSystemUsage();
             } else {
                 // TODO(b/72695246): Otherwise, get audio usage from foreground activity/window
-                return CarAudioDynamicRouting.DEFAULT_AUDIO_USAGE;
+                return DEFAULT_AUDIO_USAGE;
             }
         }
     }
diff --git a/service/src/com/android/car/audio/CarAudioZonesHelper.java b/service/src/com/android/car/audio/CarAudioZonesHelper.java
index 053c71a..f8e695d 100644
--- a/service/src/com/android/car/audio/CarAudioZonesHelper.java
+++ b/service/src/com/android/car/audio/CarAudioZonesHelper.java
@@ -25,6 +25,7 @@
 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;
@@ -33,6 +34,7 @@
 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;
@@ -46,8 +48,6 @@
  * A helper class loads all audio zones from the configuration XML file.
  */
 /* package */ class CarAudioZonesHelper {
-    private static final int INVALID_ZONE_ID = -1;
-
     private static final String NAMESPACE = null;
     private static final String TAG_ROOT = "carAudioConfiguration";
     private static final String TAG_AUDIO_ZONES = "zones";
@@ -77,7 +77,7 @@
     private static final Map<String, Integer> CONTEXT_NAME_MAP;
 
     static {
-        CONTEXT_NAME_MAP = new HashMap<>(8);
+        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);
@@ -86,12 +86,49 @@
         CONTEXT_NAME_MAP.put("alarm", CarAudioContext.ALARM);
         CONTEXT_NAME_MAP.put("notification", CarAudioContext.NOTIFICATION);
         CONTEXT_NAME_MAP.put("system_sound", CarAudioContext.SYSTEM_SOUND);
+        CONTEXT_NAME_MAP.put("emergency", CarAudioContext.EMERGENCY);
+        CONTEXT_NAME_MAP.put("safety", CarAudioContext.SAFETY);
+        CONTEXT_NAME_MAP.put("vehicle_status", CarAudioContext.VEHICLE_STATUS);
+        CONTEXT_NAME_MAP.put("announcement", CarAudioContext.ANNOUNCEMENT);
 
         SUPPORTED_VERSIONS = new SparseIntArray(2);
         SUPPORTED_VERSIONS.put(SUPPORTED_VERSION_1, SUPPORTED_VERSION_1);
         SUPPORTED_VERSIONS.put(SUPPORTED_VERSION_2, SUPPORTED_VERSION_2);
     }
 
+    // Same contexts as defined in android.hardware.automotive.audiocontrol.V1_0.ContextNumber
+    static final int[] LEGACY_CONTEXTS = new int[]{
+            CarAudioContext.MUSIC,
+            CarAudioContext.NAVIGATION,
+            CarAudioContext.VOICE_COMMAND,
+            CarAudioContext.CALL_RING,
+            CarAudioContext.CALL,
+            CarAudioContext.ALARM,
+            CarAudioContext.NOTIFICATION,
+            CarAudioContext.SYSTEM_SOUND
+    };
+
+    private static boolean isLegacyContext(@AudioContext int audioContext) {
+        return Arrays.binarySearch(LEGACY_CONTEXTS, audioContext) >= 0;
+    }
+
+    private static final List<Integer> NON_LEGACY_CONTEXTS = new ArrayList<>(
+            CarAudioContext.CONTEXTS.length - LEGACY_CONTEXTS.length);
+
+    static {
+        for (@AudioContext int audioContext : CarAudioContext.CONTEXTS) {
+            if (!isLegacyContext(audioContext)) {
+                NON_LEGACY_CONTEXTS.add(audioContext);
+            }
+        }
+    }
+
+    static void bindNonLegacyContexts(CarVolumeGroup group, CarAudioDeviceInfo info) {
+        for (@AudioContext int audioContext : NON_LEGACY_CONTEXTS) {
+            group.bind(audioContext, info);
+        }
+    }
+
     private final Context mContext;
     private final Map<String, CarAudioDeviceInfo> mAddressToCarAudioDeviceInfo;
     private final Map<String, AudioDeviceInfo> mAddressToInputAudioDeviceInfo;
@@ -232,7 +269,7 @@
 
     private int getZoneId(boolean isPrimary, XmlPullParser parser) {
         String audioZoneIdString = parser.getAttributeValue(NAMESPACE, ATTR_ZONE_ID);
-        if (mCurrentVersion == SUPPORTED_VERSION_1) {
+        if (isVersionOne()) {
             Preconditions.checkArgument(audioZoneIdString == null,
                     "Invalid audio attribute %s"
                             + ", Please update car audio configurations file "
@@ -263,7 +300,7 @@
 
     private void parseOccupantZoneId(int audioZoneId, XmlPullParser parser) {
         String occupantZoneIdString = parser.getAttributeValue(NAMESPACE, ATTR_OCCUPANT_ZONE_ID);
-        if (mCurrentVersion == SUPPORTED_VERSION_1) {
+        if (isVersionOne()) {
             Preconditions.checkArgument(occupantZoneIdString == null,
                     "Invalid audio attribute %s"
                             + ", Please update car audio configurations file "
@@ -290,7 +327,7 @@
 
     private void parseInputAudioDevices(XmlPullParser parser, CarAudioZone zone)
             throws IOException, XmlPullParserException {
-        if (mCurrentVersion == SUPPORTED_VERSION_1) {
+        if (isVersionOne()) {
             throw new IllegalStateException(
                     TAG_INPUT_DEVICES + " are not supported in car_audio_configuration.xml version "
                             + SUPPORTED_VERSION_1);
@@ -416,15 +453,26 @@
         while (parser.next() != XmlPullParser.END_TAG) {
             if (parser.getEventType() != XmlPullParser.START_TAG) continue;
             if (TAG_CONTEXT.equals(parser.getName())) {
-                int audioContext = parseCarAudioContext(
+                @AudioContext int carAudioContext = parseCarAudioContext(
                         parser.getAttributeValue(NAMESPACE, ATTR_CONTEXT_NAME));
-                group.bind(audioContext, mAddressToCarAudioDeviceInfo.get(address));
+                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();
@@ -442,10 +490,19 @@
         }
     }
 
-    private int parseCarAudioContext(String context) {
+    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() {
         int zoneId = mNextSecondaryZoneId;
         mNextSecondaryZoneId += 1;
diff --git a/service/src/com/android/car/audio/CarAudioZonesHelperLegacy.java b/service/src/com/android/car/audio/CarAudioZonesHelperLegacy.java
index cde16be..947a886 100644
--- a/service/src/com/android/car/audio/CarAudioZonesHelperLegacy.java
+++ b/service/src/com/android/car/audio/CarAudioZonesHelperLegacy.java
@@ -15,6 +15,8 @@
  */
 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;
@@ -44,15 +46,16 @@
  * @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;
 
     CarAudioZonesHelperLegacy(Context context, @XmlRes int xmlConfiguration,
@@ -62,16 +65,41 @@
         mXmlConfiguration = xmlConfiguration;
         mBusToCarAudioDeviceInfo = generateBusToCarAudioDeviceInfo(carAudioDeviceInfos);
 
-        // Initialize context => bus mapping once.
-        mContextToBus = new SparseIntArray();
+        mLegacyAudioContextToBus = loadBusesForLegacyContexts(audioControl);
+    }
+
+    /* 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 handle for IAudioControl HAL to fetch bus numbers from
+     * @return SparseIntArray mapping from {@link CarAudioContext} to bus number.
+     */
+    private static SparseIntArray loadBusesForLegacyContexts(@NonNull IAudioControl audioControl) {
+        SparseIntArray contextToBus = new SparseIntArray();
+
         try {
-            for (int contextNumber : CarAudioContext.CONTEXTS) {
-                mContextToBus.put(contextNumber, audioControl.getBusForContext(contextNumber));
+            for (int legacyContext : LEGACY_CONTEXTS) {
+                int bus = audioControl.getBusForContext(legacyContext);
+                validateBusNumber(legacyContext, bus);
+                contextToBus.put(legacyContext, bus);
             }
         } catch (RemoteException e) {
             Log.e(CarLog.TAG_AUDIO, "Failed to query IAudioControl HAL", e);
             e.rethrowAsRuntimeException();
         }
+
+        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(
@@ -82,10 +110,10 @@
             int busNumber = parseDeviceAddress(carAudioDeviceInfo.getAddress());
             if (busNumber >= 0) {
                 if (busToCarAudioDeviceInfo.get(busNumber) != null) {
-                    throw new RuntimeException("Two addresses map to same bus number: "
+                    throw new IllegalArgumentException("Two addresses map to same bus number: "
                             + carAudioDeviceInfo.getAddress()
                             + " and "
-                    + busToCarAudioDeviceInfo.get(busNumber).getAddress());
+                            + busToCarAudioDeviceInfo.get(busNumber).getAddress());
                 }
                 busToCarAudioDeviceInfo.put(busNumber, carAudioDeviceInfo);
             }
@@ -99,13 +127,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, 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 };
     }
 
     /**
@@ -123,7 +159,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;
@@ -169,6 +206,7 @@
 
     /**
      * 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) {
diff --git a/service/src/com/android/car/audio/FocusInteraction.java b/service/src/com/android/car/audio/FocusInteraction.java
index 144d7a1..b3d0ff0 100644
--- a/service/src/com/android/car/audio/FocusInteraction.java
+++ b/service/src/com/android/car/audio/FocusInteraction.java
@@ -59,7 +59,11 @@
                     INTERACTION_REJECT, // CALL
                     INTERACTION_REJECT, // ALARM
                     INTERACTION_REJECT, // NOTIFICATION
-                    INTERACTION_REJECT, // SYSTEM_SOUND
+                    INTERACTION_REJECT, // SYSTEM_SOUND,
+                    INTERACTION_EXCLUSIVE, // EMERGENCY
+                    INTERACTION_EXCLUSIVE, // SAFETY
+                    INTERACTION_REJECT, // VEHICLE_STATUS
+                    INTERACTION_REJECT, // ANNOUNCEMENT
             },
             // Focus holder: MUSIC
             {
@@ -71,7 +75,11 @@
                     INTERACTION_EXCLUSIVE, // CALL
                     INTERACTION_EXCLUSIVE, // ALARM
                     INTERACTION_CONCURRENT, // NOTIFICATION
-                    INTERACTION_CONCURRENT,  // SYSTEM_SOUND
+                    INTERACTION_CONCURRENT, // SYSTEM_SOUND
+                    INTERACTION_EXCLUSIVE, // EMERGENCY
+                    INTERACTION_CONCURRENT, // SAFETY
+                    INTERACTION_CONCURRENT, // VEHICLE_STATUS
+                    INTERACTION_EXCLUSIVE, // ANNOUNCEMENT
             },
             // Focus holder: NAVIGATION
             {
@@ -83,7 +91,11 @@
                     INTERACTION_EXCLUSIVE, // CALL
                     INTERACTION_CONCURRENT, // ALARM
                     INTERACTION_CONCURRENT, // NOTIFICATION
-                    INTERACTION_CONCURRENT,  // SYSTEM_SOUND
+                    INTERACTION_CONCURRENT, // SYSTEM_SOUND
+                    INTERACTION_EXCLUSIVE, // EMERGENCY
+                    INTERACTION_CONCURRENT, // SAFETY
+                    INTERACTION_CONCURRENT, // VEHICLE_STATUS
+                    INTERACTION_CONCURRENT, // ANNOUNCEMENT
             },
             // Focus holder: VOICE_COMMAND
             {
@@ -96,6 +108,10 @@
                     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
             {
@@ -108,6 +124,10 @@
                     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
             {
@@ -120,6 +140,10 @@
                     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
             {
@@ -132,6 +156,10 @@
                     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
             {
@@ -144,6 +172,10 @@
                     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
             {
@@ -156,6 +188,74 @@
                     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
             },
     };
 
diff --git a/service/src/com/android/car/hal/InputHalService.java b/service/src/com/android/car/hal/InputHalService.java
index 1c8fb8d..d05ceff 100644
--- a/service/src/com/android/car/hal/InputHalService.java
+++ b/service/src/com/android/car/hal/InputHalService.java
@@ -15,7 +15,10 @@
  */
 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.hardware.automotive.vehicle.V2_0.VehicleDisplay;
 import android.hardware.automotive.vehicle.V2_0.VehicleHwKeyInputAction;
@@ -35,6 +38,7 @@
 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 {
@@ -42,7 +46,10 @@
     public static final int DISPLAY_MAIN = VehicleDisplay.MAIN;
     public static final int DISPLAY_INSTRUMENT_CLUSTER = VehicleDisplay.INSTRUMENT_CLUSTER;
     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 {
@@ -59,10 +66,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 +91,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,9 +131,10 @@
 
     @Override
     public void release() {
-        synchronized (this) {
+        synchronized (mLock) {
             mListener = null;
             mKeyInputSupported = false;
+            mRotaryInputSupported = false;
         }
     }
 
@@ -109,12 +142,20 @@
     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;
-                }
+        for (VehiclePropConfig property : allProperties) {
+            switch (property.prop) {
+                case HW_KEY_INPUT:
+                    supported.add(property);
+                    synchronized (mLock) {
+                        mKeyInputSupported = true;
+                    }
+                    break;
+                case HW_ROTARY_INPUT:
+                    supported.add(property);
+                    synchronized (mLock) {
+                        mRotaryInputSupported = true;
+                    }
+                    break;
             }
         }
         return supported;
@@ -123,42 +164,124 @@
     @Override
     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 rotaryInputType = value.value.int32Values.get(0);
+        int detentCount = value.value.int32Values.get(1);
+        int display = value.value.int32Values.get(2);
+        int intValuesIndex = 3;  // remaining values are time deltas in nanoseconds
+        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());
+        }
+
+        int keycode;
+        switch (rotaryInputType) {
+            case ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION:
+                // TODO(depstein): Send rotary events directly to RotaryService.
+                keycode = detentCount > 0
+                        ? KeyEvent.KEYCODE_NAVIGATE_NEXT
+                        : KeyEvent.KEYCODE_NAVIGATE_PREVIOUS;
+                break;
+            case ROTARY_INPUT_TYPE_AUDIO_VOLUME:
+                keycode = detentCount > 0
+                        ? KeyEvent.KEYCODE_VOLUME_UP
+                        : KeyEvent.KEYCODE_VOLUME_DOWN;
+                break;
+            default:
+                Log.e(CarLog.TAG_INPUT, "Unknown rotary input type: " + rotaryInputType);
+                return;
+        }
+
+        detentCount = Math.abs(detentCount);
+        if (detentCount - 1 != value.value.int32Values.size() - 3) {
+            Log.e(CarLog.TAG_INPUT,
+                    String.format("Prop should include %d time deltas, found %d", detentCount - 1,
+                            value.value.int32Values.size() - 3));
+        }
+
+        while (detentCount > 0) {
+            detentCount--;
+            long eventTimeMillis = TimeUnit.NANOSECONDS.toMillis(timestamp);
+            dispatchKeyEvent(listener, KeyEvent.ACTION_DOWN, keycode, display, eventTimeMillis);
+            dispatchKeyEvent(listener, KeyEvent.ACTION_UP, keycode, display, eventTimeMillis);
+            if (intValuesIndex < value.value.int32Values.size()) {
+                timestamp += value.value.int32Values.get(intValuesIndex);
+                intValuesIndex++;
+            }
+        }
+    }
+
+    /**
+     * 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;
 
@@ -207,6 +330,6 @@
     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/UserHalHelper.java b/service/src/com/android/car/hal/UserHalHelper.java
index d5311dc..d5b677d 100644
--- a/service/src/com/android/car/hal/UserHalHelper.java
+++ b/service/src/com/android/car/hal/UserHalHelper.java
@@ -57,7 +57,7 @@
      * @throws IllegalArgumentException if type is not valid neither a number
      */
     public static int parseInitialUserInfoRequestType(@NonNull String type) {
-        // TODO(b/146207078): add unit test
+        // TODO(b/150419600): add unit test
         switch(type) {
             case "FIRST_BOOT":
                 return InitialUserInfoRequestType.FIRST_BOOT;
@@ -80,7 +80,7 @@
      * Converts Android user flags to HALs.
      */
     public static int convertFlags(@NonNull UserInfo user) {
-        // TODO(b/146207078): add unit test
+        // TODO(b/150419600): add unit test
         int flags = UserFlags.NONE;
         if (user.id == UserHandle.USER_SYSTEM) {
             flags |= UserFlags.SYSTEM;
diff --git a/service/src/com/android/car/hal/UserHalService.java b/service/src/com/android/car/hal/UserHalService.java
index 1d6dc6f..7b26e82 100644
--- a/service/src/com/android/car/hal/UserHalService.java
+++ b/service/src/com/android/car/hal/UserHalService.java
@@ -34,6 +34,7 @@
 import android.os.Looper;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.sysprop.CarProperties;
 import android.util.Log;
 import android.util.Pair;
 import android.util.Slog;
@@ -50,6 +51,7 @@
 import java.util.Collection;
 import java.util.List;
 import java.util.Objects;
+import java.util.Optional;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
@@ -62,7 +64,7 @@
 
     private static final String TAG = UserHalService.class.getSimpleName();
 
-    // TODO(b/146207078): STOPSHIP - change to false before R is launched
+    // TODO(b/150413515): STOPSHIP - change to false before R is launched
     private static final boolean DBG = true;
 
     private static final int REQUEST_TYPE_GET_INITIAL_INFO = 1;
@@ -399,14 +401,19 @@
 
     @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();
-            String indent = "  ";
             writer.printf("%d supported properties\n", numberProperties);
             for (int i = 0; i < numberProperties; i++) {
                 writer.printf("%s%s\n", indent, mProperties.valueAt(i));
@@ -437,6 +444,12 @@
         }
     }
 
+    private 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);
+    }
+
     /**
      * Dumps the state that's guarded by {@code mHandler}.
      */
diff --git a/service/src/com/android/car/trust/BlePeripheralManager.java b/service/src/com/android/car/trust/BlePeripheralManager.java
index d582708..17528f4 100644
--- a/service/src/com/android/car/trust/BlePeripheralManager.java
+++ b/service/src/com/android/car/trust/BlePeripheralManager.java
@@ -48,7 +48,8 @@
  * 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.
+ * @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 {
diff --git a/service/src/com/android/car/trust/CarBleTrustAgent.java b/service/src/com/android/car/trust/CarBleTrustAgent.java
index 428327c..657b76f 100644
--- a/service/src/com/android/car/trust/CarBleTrustAgent.java
+++ b/service/src/com/android/car/trust/CarBleTrustAgent.java
@@ -49,7 +49,8 @@
  * 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.
+ * @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 {
diff --git a/service/src/com/android/car/trust/CarTrustAgentEnrollmentService.java b/service/src/com/android/car/trust/CarTrustAgentEnrollmentService.java
index 412d3ea..bff833a 100644
--- a/service/src/com/android/car/trust/CarTrustAgentEnrollmentService.java
+++ b/service/src/com/android/car/trust/CarTrustAgentEnrollmentService.java
@@ -86,7 +86,8 @@
  * 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.
+ * @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.
  */
 @Deprecated
 public class CarTrustAgentEnrollmentService extends ICarTrustAgentEnrollment.Stub implements
diff --git a/service/src/com/android/car/trust/CarTrustAgentUnlockService.java b/service/src/com/android/car/trust/CarTrustAgentUnlockService.java
index e3129bd..a163dba 100644
--- a/service/src/com/android/car/trust/CarTrustAgentUnlockService.java
+++ b/service/src/com/android/car/trust/CarTrustAgentUnlockService.java
@@ -88,7 +88,8 @@
  * <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.
+ * @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 {
diff --git a/service/src/com/android/car/trust/CarTrustedDeviceService.java b/service/src/com/android/car/trust/CarTrustedDeviceService.java
index b339179..972ff64 100644
--- a/service/src/com/android/car/trust/CarTrustedDeviceService.java
+++ b/service/src/com/android/car/trust/CarTrustedDeviceService.java
@@ -36,7 +36,8 @@
  * 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.
+ * @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.
  */
 @Deprecated
 public class CarTrustedDeviceService implements CarServiceBase, BleEventCallback {
diff --git a/service/src/com/android/car/user/CarUserService.java b/service/src/com/android/car/user/CarUserService.java
index ed9a59c..fedae06 100644
--- a/service/src/com/android/car/user/CarUserService.java
+++ b/service/src/com/android/car/user/CarUserService.java
@@ -499,7 +499,8 @@
                             resultData.putString(BUNDLE_USER_NAME, resp.userNameToCreate);
                             break;
                         case InitialUserInfoResponseAction.DEFAULT:
-                            // do nothing
+                            resultData = new Bundle();
+                            resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
                             break;
                         default:
                             // That's ok, it will be the same as DEFAULT...
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/CryptKeeper.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/CryptKeeper.java
index c7b372e..2727507 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/CryptKeeper.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/CryptKeeper.java
@@ -915,7 +915,7 @@
      *    phone that has no encryption.
      */
     private final void setAirplaneModeIfNecessary() {
-        if (!getTelephonyManager().isGlobalModeEnabled()) {
+        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);
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 e1c041c..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
@@ -141,7 +141,7 @@
 
     @VisibleForTesting
     boolean isCdmaLteEnabled() {
-        return mTelephonyManager.isGlobalModeEnabled();
+        return mTelephonyManager.isLteCdmaEvdoGsmWcdmaEnabled();
     }
 
     @VisibleForTesting
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 847b35c..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
@@ -52,7 +52,7 @@
                 && carrierConfig != null
                 && !carrierConfig.getBoolean(
                 CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL)
-                && mTelephonyManager.isGlobalModeEnabled() && !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 f99ae0f..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
@@ -107,7 +107,7 @@
         final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(mSubId);
         mTelephonyManager = TelephonyManager.from(mContext).createForSubscriptionId(mSubId);
 
-        mIsGlobalCdma = mTelephonyManager.isGlobalModeEnabled()
+        mIsGlobalCdma = mTelephonyManager.isLteCdmaEvdoGsmWcdmaEnabled()
                 && carrierConfig.getBoolean(CarrierConfigManager.KEY_SHOW_CDMA_CHOICES_BOOL);
         mShow4GForLTE = carrierConfig != null
                 ? carrierConfig.getBoolean(
@@ -133,7 +133,7 @@
                     mContext.getContentResolver(),
                     android.provider.Settings.Global.PREFERRED_NETWORK_MODE + mSubId,
                     Phone.PREFERRED_NT_MODE);
-            if (mTelephonyManager.isGlobalModeEnabled()) {
+            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/PreferredNetworkModePreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/telephony/PreferredNetworkModePreferenceController.java
index 29e4f03..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
@@ -103,7 +103,7 @@
         final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(mSubId);
         mTelephonyManager = TelephonyManager.from(mContext).createForSubscriptionId(mSubId);
 
-        mIsGlobalCdma = mTelephonyManager.isGlobalModeEnabled()
+        mIsGlobalCdma = mTelephonyManager.isLteCdmaEvdoGsmWcdmaEnabled()
                 && carrierConfig.getBoolean(CarrierConfigManager.KEY_SHOW_CDMA_CHOICES_BOOL);
     }
 
@@ -130,7 +130,7 @@
             case TelephonyManager.NETWORK_MODE_GSM_UMTS:
                 return R.string.preferred_network_mode_gsm_wcdma_summary;
             case TelephonyManager.NETWORK_MODE_CDMA_EVDO:
-                return mTelephonyManager.isGlobalModeEnabled()
+                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:
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 df9aa7b..f753efe 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
@@ -116,7 +116,7 @@
             return;
         }
         Log.d(TAG, "Connected to Car Service");
-        mCarAudioManager = (CarAudioManager) mCar.getCarManager(Car.AUDIO_SERVICE);
+        mCarAudioManager = (CarAudioManager) car.getCarManager(Car.AUDIO_SERVICE);
         initVolumeInfo();
     };
 
diff --git a/tests/carservice_test/res/raw/car_audio_configuration.xml b/tests/carservice_test/res/raw/car_audio_configuration.xml
index 2d7c609..b4bb08a 100644
--- a/tests/carservice_test/res/raw/car_audio_configuration.xml
+++ b/tests/carservice_test/res/raw/car_audio_configuration.xml
@@ -14,6 +14,10 @@
                 <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>
@@ -32,8 +36,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_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..03e9a0f
--- /dev/null
+++ b/tests/carservice_test/res/raw/car_audio_configuration_V1_with_non_legacy_contexts.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<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>
+            <displays>
+                <display port="1"/>
+                <display port="2"/>
+            </displays>
+        </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_duplicate_audio_zone_id.xml b/tests/carservice_test/res/raw/car_audio_configuration_duplicate_audio_zone_id.xml
index 2743c41..4b5abc5 100644
--- 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
@@ -30,6 +30,10 @@
                 <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>
@@ -50,6 +54,10 @@
                         <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>
@@ -66,6 +74,10 @@
                         <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>
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
index 613f6cd..1d15b36 100644
--- 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
@@ -30,6 +30,10 @@
                 <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>
@@ -50,6 +54,10 @@
                         <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>
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
index d2ff43d..9a7b2d6 100644
--- 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
@@ -30,6 +30,10 @@
                 <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>
@@ -50,6 +54,10 @@
                         <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>
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
index c4ef494..182e606 100644
--- 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
@@ -30,6 +30,10 @@
                 <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>
@@ -50,6 +54,10 @@
                         <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>
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
index 7af8d68..a3ab43d 100644
--- a/tests/carservice_test/res/raw/car_audio_configuration_missing_address.xml
+++ b/tests/carservice_test/res/raw/car_audio_configuration_missing_address.xml
@@ -30,6 +30,10 @@
                 <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>
@@ -50,6 +54,10 @@
                         <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>
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
index 3c202f3..acdb784 100644
--- 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
@@ -30,6 +30,10 @@
                 <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>
@@ -50,6 +54,10 @@
                         <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>
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
index ac240d6..b7d7a62 100644
--- 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
@@ -30,6 +30,10 @@
                 <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>
@@ -50,6 +54,10 @@
                         <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>
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
index 720e875..8cf6c13 100644
--- 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
@@ -30,6 +30,10 @@
                 <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>
@@ -47,6 +51,10 @@
                         <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>
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
index 2f317d0..d4ddfbe 100644
--- 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
@@ -30,6 +30,10 @@
                 <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>
@@ -50,6 +54,10 @@
                         <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>
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
index 2721b50..09168a6 100644
--- 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
@@ -30,6 +30,10 @@
                 <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>
@@ -50,6 +54,10 @@
                         <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>
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
index 85dd768..af57c24 100644
--- 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
@@ -30,6 +30,10 @@
                 <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>
@@ -50,6 +54,10 @@
                         <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>
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..f6995bc 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,6 +14,10 @@
                 <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>
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
index d6889f6..f822469 100644
--- 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
@@ -50,6 +50,10 @@
                         <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>
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
index ff6fe8a..83c054c 100644
--- 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
@@ -30,6 +30,10 @@
                 <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>
@@ -50,6 +54,10 @@
                         <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>
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
index ee0b268..6f845e7 100644
--- 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
@@ -30,6 +30,10 @@
                 <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>
@@ -50,6 +54,10 @@
                         <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>
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
index 1934fe7..efe1e5e 100644
--- 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
@@ -30,6 +30,10 @@
                 <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>
@@ -50,6 +54,10 @@
                         <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>
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
index 3b6a013..f97d835 100644
--- 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
@@ -30,6 +30,10 @@
                 <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>
@@ -50,6 +54,10 @@
                         <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>
diff --git a/tests/carservice_test/res/xml/car_volume_groups.xml b/tests/carservice_test/res/xml/car_volume_groups.xml
new file mode 100644
index 0000000..9d25cf8
--- /dev/null
+++ b/tests/carservice_test/res/xml/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/com/android/car/CarPowerManagementTest.java b/tests/carservice_test/src/com/android/car/CarPowerManagementTest.java
index 4d1c9df..adfb98b 100644
--- a/tests/carservice_test/src/com/android/car/CarPowerManagementTest.java
+++ b/tests/carservice_test/src/com/android/car/CarPowerManagementTest.java
@@ -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;
@@ -53,7 +54,8 @@
 public class CarPowerManagementTest extends MockedCarTestBase {
 
     private static final int STATE_POLLING_INTERVAL_MS = 1; // Milliseconds
-    private static final int TEST_SHUTDOWN_TIMEOUT_MS = 10 * STATE_POLLING_INTERVAL_MS;
+    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();
@@ -400,7 +402,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)) {
@@ -409,7 +411,7 @@
                 synchronized (this) {
                     boolean found = false;
                     for (int[] state : mSetStates) {
-                        if (state[0] == expectedSet) {
+                        if (state[0] == expectedState) {
                             found = true;
                             break;
                         }
@@ -424,10 +426,10 @@
             }
         }
 
-        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);
         }
 
         /**
@@ -437,18 +439,28 @@
         private void sendStateAndExpectNoResponse(int state, int param) throws Exception {
             sendPowerState(state, param);
             // Wait to see if a state transition occurs
-            if (!mSetWaitSemaphore.tryAcquire(TEST_SHUTDOWN_TIMEOUT_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 occurred, state=" + newState[0]);
+            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;
                 }
-                // Reset the collected states
-                mSetStates = new LinkedList<>();
-                mSetWaitSemaphore.drainPermits();
+                if (!mSetWaitSemaphore.tryAcquire(STATE_TRANSITION_MAX_WAIT_MS,
+                        TimeUnit.MILLISECONDS)) {
+                    // No state transition, this is a success!
+                    return;
+                }
+                synchronized (this) {
+                    while (!mSetStates.isEmpty()) {
+                        int[] newState = mSetStates.pop();
+                        if (newState[0] != VehicleApPowerStateReport.SHUTDOWN_POSTPONE) {
+                            fail("Unexpected state change occurred, state="
+                                    + Arrays.toString(newState));
+                        }
+                    }
+                    mSetWaitSemaphore.drainPermits();
+                }
             }
         }
 
diff --git a/tests/carservice_test/src/com/android/car/audio/CarAudioFocusTest.java b/tests/carservice_test/src/com/android/car/audio/CarAudioFocusTest.java
index e481de1..89bbb08 100644
--- a/tests/carservice_test/src/com/android/car/audio/CarAudioFocusTest.java
+++ b/tests/carservice_test/src/com/android/car/audio/CarAudioFocusTest.java
@@ -38,12 +38,12 @@
 @RunWith(AndroidJUnit4.class)
 public class CarAudioFocusTest {
     private static final int TEST_TIMING_TOLERANCE_MS = 100;
-    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
+    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_VIRTUAL_SOURCE = new AudioAttributes.Builder()
+    private static final AudioAttributes ATTR_INVALID = new AudioAttributes.Builder()
             .setUsage(AudioAttributes.USAGE_VIRTUAL_SOURCE)
             .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
             .build();
@@ -53,22 +53,22 @@
             .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
             .build();
     // CarAudioContext.NAVIGATION
-    private static final AudioAttributes ATTR_DRIVE_DIR = new AudioAttributes.Builder()
+    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_A11Y = new AudioAttributes.Builder()
+    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_RINGTONE = new AudioAttributes.Builder()
+    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_VOICE_COM = new AudioAttributes.Builder()
+    private static final AudioAttributes ATTR_CALL = new AudioAttributes.Builder()
             .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
             .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
             .build();
@@ -83,10 +83,30 @@
             .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
             .build();
     // CarAudioContext.SYSTEM_SOUND
-    private static final AudioAttributes ATTR_A11Y_NOTIFICATION = new AudioAttributes.Builder()
+    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 AudioManager mAudioManager;
 
@@ -104,15 +124,19 @@
     @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_INVALID);
         requestAndLoseFocusForAttribute(ATTR_MEDIA);
-        requestAndLoseFocusForAttribute(ATTR_DRIVE_DIR);
-        requestAndLoseFocusForAttribute(ATTR_A11Y);
-        requestAndLoseFocusForAttribute(ATTR_RINGTONE);
-        requestAndLoseFocusForAttribute(ATTR_VOICE_COM);
+        requestAndLoseFocusForAttribute(ATTR_NAVIGATION);
+        requestAndLoseFocusForAttribute(ATTR_VOICE_COMMAND);
+        requestAndLoseFocusForAttribute(ATTR_CALL_RING);
+        requestAndLoseFocusForAttribute(ATTR_CALL);
         requestAndLoseFocusForAttribute(ATTR_ALARM);
         requestAndLoseFocusForAttribute(ATTR_NOTIFICATION);
-        requestAndLoseFocusForAttribute(ATTR_A11Y_NOTIFICATION);
+        requestAndLoseFocusForAttribute(ATTR_SYSTEM_SOUND);
+        requestAndLoseFocusForAttribute(ATTR_EMERGENCY);
+        requestAndLoseFocusForAttribute(ATTR_SAFETY);
+        requestAndLoseFocusForAttribute(ATTR_VEHICLE_STATUS);
+        requestAndLoseFocusForAttribute(ATTR_ANNOUNCEMENT);
     }
 
     @Test
@@ -152,12 +176,10 @@
 
         // Test exclusive interactions with audio focus transient may duck focus request
         // without pause instead of ducking
-        testExclusiveInteractions(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
-                false);
+        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);
+        testExclusiveInteractions(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, true);
     }
 
     @RequiresDevice
@@ -168,39 +190,63 @@
         // will be rejected
         int interaction = 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_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_VIRTUAL_SOURCE, interaction, gain, false);
+        testInteraction(ATTR_MEDIA, ATTR_INVALID, interaction, gain, false);
 
-        testInteraction(ATTR_DRIVE_DIR, ATTR_VIRTUAL_SOURCE, interaction, gain, false);
+        testInteraction(ATTR_NAVIGATION, ATTR_INVALID, 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_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_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_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_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_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_VIRTUAL_SOURCE, interaction, gain, false);
+        testInteraction(ATTR_ALARM, ATTR_INVALID, interaction, gain, false);
+        testInteraction(ATTR_ALARM, ATTR_ANNOUNCEMENT, interaction, gain, false);
 
-        testInteraction(ATTR_NOTIFICATION, ATTR_VIRTUAL_SOURCE, interaction, gain, false);
+        testInteraction(ATTR_NOTIFICATION, ATTR_INVALID, interaction, gain, false);
 
-        testInteraction(ATTR_A11Y_NOTIFICATION, ATTR_VIRTUAL_SOURCE, 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
@@ -248,52 +294,103 @@
         // Test paired concurrent interactions i.e. interactions that can
         // potentially gain focus at the same time.
         int interaction = INTERACTION_CONCURRENT;
-        testInteraction(ATTR_MEDIA, ATTR_DRIVE_DIR, interaction, gain, pauseForDucking);
+        testInteraction(ATTR_MEDIA, ATTR_NAVIGATION, interaction, gain, pauseForDucking);
         testInteraction(ATTR_MEDIA, ATTR_NOTIFICATION, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_MEDIA, ATTR_A11Y_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_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_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_A11Y, ATTR_MEDIA, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_A11Y, ATTR_A11Y, 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_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_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_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_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_DRIVE_DIR, 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_A11Y_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_DRIVE_DIR, 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_A11Y_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_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,
+        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_A11Y_NOTIFICATION, ATTR_A11Y_NOTIFICATION, 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)
@@ -303,43 +400,69 @@
         // 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_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_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_DRIVE_DIR, ATTR_A11Y, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_DRIVE_DIR, ATTR_VOICE_COM, 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_A11Y, ATTR_RINGTONE, interaction, gain, pauseForDucking);
-        testInteraction(ATTR_A11Y, ATTR_VOICE_COM, 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_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_CALL_RING, ATTR_EMERGENCY, 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_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_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);
+        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 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
+     *
+     * @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 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,
@@ -392,13 +515,12 @@
 
         int requestResult = mAudioManager.requestAudioFocus(audioFocusRequest1);
         String message = "Focus gain request failed  for 1st "
-                + AudioAttributes.usageToString(attributes1.getUsage());
+                + AudioAttributes.usageToString(attributes1.getSystemUsage());
         assertEquals(message, AudioManager.AUDIOFOCUS_REQUEST_GRANTED, requestResult);
 
-
         requestResult = mAudioManager.requestAudioFocus(audioFocusRequest2);
         message = "Focus gain request failed for 2nd "
-                + AudioAttributes.usageToString(attributes2.getUsage());
+                + AudioAttributes.usageToString(attributes2.getSystemUsage());
         assertEquals(message, secondRequestResultsExpected, requestResult);
 
         // If the results is rejected for second one we only have to clean up first
@@ -406,7 +528,7 @@
         if (interaction == INTERACTION_REJECT) {
             requestResult = mAudioManager.abandonAudioFocusRequest(audioFocusRequest1);
             message = "Focus loss request failed for 1st "
-                    + AudioAttributes.usageToString(attributes1.getUsage());
+                    + AudioAttributes.usageToString(attributes1.getSystemUsage());
             assertEquals(message, AudioManager.AUDIOFOCUS_REQUEST_GRANTED, requestResult);
         }
 
@@ -415,13 +537,13 @@
         if (interaction == INTERACTION_EXCLUSIVE || interaction == INTERACTION_CONCURRENT) {
             Thread.sleep(TEST_TIMING_TOLERANCE_MS);
             message = "Focus change was not dispatched for 1st "
-                    + AudioAttributes.usageToString(ATTR_MEDIA.getUsage());
+                    + AudioAttributes.usageToString(ATTR_MEDIA.getSystemUsage());
             assertEquals(message, expectedLoss,
                     focusChangeListener1.getFocusChangeAndReset());
 
             requestResult = mAudioManager.abandonAudioFocusRequest(audioFocusRequest2);
             message = "Focus loss request failed  for 2nd "
-                    + AudioAttributes.usageToString(ATTR_MEDIA.getUsage());
+                    + AudioAttributes.usageToString(ATTR_MEDIA.getSystemUsage());
             assertEquals(message, AudioManager.AUDIOFOCUS_REQUEST_GRANTED, requestResult);
 
             // If the loss was transient then we should have received back on 1st
@@ -434,13 +556,13 @@
                         && 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());
+                            + AudioAttributes.usageToString(ATTR_MEDIA.getSystemUsage());
                     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());
+                        + AudioAttributes.usageToString(attributes1.getSystemUsage());
                 requestResult = mAudioManager.abandonAudioFocusRequest(audioFocusRequest1);
                 assertEquals(message, AudioManager.AUDIOFOCUS_REQUEST_GRANTED,
                         requestResult);
@@ -450,10 +572,11 @@
 
     /**
      * 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 {
+    private void requestAndLoseFocusForAttribute(AudioAttributes attribute) throws Exception {
         final FocusChangeListener focusChangeListener = new FocusChangeListener();
         final AudioFocusRequest audioFocusRequest = new AudioFocusRequest
                 .Builder(AudioManager.AUDIOFOCUS_GAIN)
@@ -465,19 +588,19 @@
 
         int requestResult = mAudioManager.requestAudioFocus(audioFocusRequest);
         String message = "Focus gain request failed  for "
-                + AudioAttributes.usageToString(attribute.getUsage());
+                + AudioAttributes.usageToString(attribute.getSystemUsage());
         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());
+                + AudioAttributes.usageToString(attribute.getSystemUsage());
         assertEquals(message, AudioManager.AUDIOFOCUS_NONE,
                 focusChangeListener.getFocusChangeAndReset());
 
         requestResult = mAudioManager.abandonAudioFocusRequest(audioFocusRequest);
         message = "Focus loss request failed  for "
-                + AudioAttributes.usageToString(attribute.getUsage());
+                + AudioAttributes.usageToString(attribute.getSystemUsage());
         assertEquals(message, AudioManager.AUDIOFOCUS_REQUEST_GRANTED, requestResult);
     }
 
diff --git a/tests/carservice_test/src/com/android/car/audio/CarAudioZonesHelperLegacyTest.java b/tests/carservice_test/src/com/android/car/audio/CarAudioZonesHelperLegacyTest.java
index 1fda2ed..973bee4 100644
--- a/tests/carservice_test/src/com/android/car/audio/CarAudioZonesHelperLegacyTest.java
+++ b/tests/carservice_test/src/com/android/car/audio/CarAudioZonesHelperLegacyTest.java
@@ -15,47 +15,161 @@
  */
 package com.android.car.audio;
 
-import static org.mockito.Mockito.when;
+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 android.hardware.automotive.audiocontrol.V1_0.IAudioControl;
 
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
+import com.android.car.R;
+
 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.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 ExpectedException thrown = ExpectedException.none();
+    public final MockitoRule rule = MockitoJUnit.rule();
+
+    @Mock
+    private IAudioControl mMockAudioControl;
+
+    private static final int INVALID_BUS = -1;
+    private final Context mContext = ApplicationProvider.getApplicationContext();
+    private final @XmlRes int mCarVolumeGroups = R.xml.car_volume_groups;
 
     @Test
     public void constructor_checksForNoDuplicateBusNumbers() {
-        Context context = ApplicationProvider.getApplicationContext();
+        List<CarAudioDeviceInfo> carAudioDeviceInfos = getCarAudioDeviceInfoWithDuplicateBuses();
 
-        IAudioControl mockAudioControl = Mockito.mock(IAudioControl.class);
+        RuntimeException exception = expectThrows(RuntimeException.class,
+                () -> new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
+                        carAudioDeviceInfos, mMockAudioControl));
 
+        assertThat(exception.getMessage()).contains("Two addresses map to same bus number:");
+    }
+
+    @Test
+    public void constructor_throwsIfLegacyContextNotAssignedToBus() throws Exception {
+        List<CarAudioDeviceInfo> carAudioDeviceInfos = getValidCarAudioDeviceInfos();
+
+        when(mMockAudioControl.getBusForContext(anyInt())).thenReturn(INVALID_BUS);
+
+        RuntimeException exception = expectThrows(RuntimeException.class,
+                () -> new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
+                carAudioDeviceInfos, mMockAudioControl));
+
+        assertThat(exception.getMessage()).contains("Invalid bus -1 was associated with context");
+    }
+
+    @Test
+    public void loadAudioZones_succeeds() throws Exception {
+        List<CarAudioDeviceInfo> carAudioDeviceInfos = getValidCarAudioDeviceInfos();
+        when(mMockAudioControl.getBusForContext(anyInt())).thenReturn(1);
+
+        CarAudioZonesHelperLegacy helper = new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
+                carAudioDeviceInfos, mMockAudioControl);
+
+        CarAudioZone[] zones = helper.loadAudioZones();
+
+        assertThat(zones).hasLength(1);
+    }
+
+    @Test
+    public void loadAudioZones_parsesAllVolumeGroups() throws Exception {
+        List<CarAudioDeviceInfo> carAudioDeviceInfos = getValidCarAudioDeviceInfos();
+
+        when(mMockAudioControl.getBusForContext(anyInt())).thenReturn(1);
+
+        CarAudioZonesHelperLegacy helper = new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
+                carAudioDeviceInfos, mMockAudioControl);
+
+        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(mMockAudioControl.getBusForContext(anyInt())).thenReturn(2);
+        when(mMockAudioControl.getBusForContext(CarAudioContext.MUSIC)).thenReturn(1);
+
+        CarAudioZonesHelperLegacy helper = new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
+                carAudioDeviceInfos, mMockAudioControl);
+
+        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(mMockAudioControl.getBusForContext(anyInt())).thenReturn(2);
+        when(mMockAudioControl.getBusForContext(CarAudioService.DEFAULT_AUDIO_CONTEXT))
+                .thenReturn(1);
+
+        CarAudioZonesHelperLegacy helper = new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
+                carAudioDeviceInfos, mMockAudioControl);
+
+        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");
-        List<CarAudioDeviceInfo> carAudioDeviceInfos = Lists.newArrayList(deviceInfo1, deviceInfo2);
+        return Lists.newArrayList(deviceInfo1, deviceInfo2);
+    }
 
-        thrown.expect(RuntimeException.class);
-        thrown.expectMessage(
-                "Two addresses map to same bus number: bus001_notifications and bus001_media");
-
-        new CarAudioZonesHelperLegacy(context, 1,
-                carAudioDeviceInfos, mockAudioControl);
+    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 631e85c..fdb7c38 100644
--- a/tests/carservice_test/src/com/android/car/audio/CarAudioZonesHelperTest.java
+++ b/tests/carservice_test/src/com/android/car/audio/CarAudioZonesHelperTest.java
@@ -15,9 +15,9 @@
  */
 package com.android.car.audio;
 
-import static com.google.common.truth.Truth.assertThat;
+import static com.android.car.audio.CarAudioService.DEFAULT_AUDIO_CONTEXT;
 
-import static junit.framework.TestCase.fail;
+import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
@@ -45,7 +45,6 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -102,7 +101,7 @@
     }
 
     private AudioDeviceInfo[] generateInputDeviceInfos() {
-        return new AudioDeviceInfo[] {
+        return new AudioDeviceInfo[]{
                 generateInputAudioDeviceInfo(PRIMARY_ZONE_MICROPHONE_ADDRESS,
                         AudioDeviceInfo.TYPE_BUILTIN_MIC),
                 generateInputAudioDeviceInfo(PRIMARY_ZONE_FM_TUNER_ADDRESS,
@@ -187,7 +186,7 @@
     }
 
     @Test
-    public void loadAudioZones_parsesZoneName() throws IOException, XmlPullParserException {
+    public void loadAudioZones_parsesZoneName() throws Exception {
         CarAudioZonesHelper cazh = new CarAudioZonesHelper(mContext, mInputStream,
                 mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
 
@@ -198,7 +197,7 @@
     }
 
     @Test
-    public void loadAudioZones_parsesIsPrimary() throws IOException, XmlPullParserException {
+    public void loadAudioZones_parsesIsPrimary() throws Exception {
         CarAudioZonesHelper cazh = new CarAudioZonesHelper(mContext, mInputStream,
                 mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
 
@@ -212,7 +211,7 @@
     }
 
     @Test
-    public void loadAudioZones_parsesVolumeGroups() throws IOException, XmlPullParserException {
+    public void loadAudioZones_parsesVolumeGroups() throws Exception {
         CarAudioZonesHelper cazh = new CarAudioZonesHelper(mContext, mInputStream,
                 mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
 
@@ -223,7 +222,7 @@
     }
 
     @Test
-    public void loadAudioZones_parsesAddresses() throws IOException, XmlPullParserException {
+    public void loadAudioZones_parsesAddresses() throws Exception {
         CarAudioZonesHelper cazh = new CarAudioZonesHelper(mContext, mInputStream,
                 mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
 
@@ -238,7 +237,7 @@
     }
 
     @Test
-    public void loadAudioZones_parsesContexts() throws IOException, XmlPullParserException {
+    public void loadAudioZones_parsesContexts() throws Exception {
         CarAudioZonesHelper cazh = new CarAudioZonesHelper(mContext, mInputStream,
                 mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
 
@@ -257,8 +256,41 @@
     }
 
     @Test
-    public void loadAudioZones_parsesPhysicalDisplayAddresses()
-            throws IOException, XmlPullParserException {
+    public void loadAudioZones_forVersionOne_bindsNonLegacyContextsToDefault() throws Exception {
+        InputStream versionOneStream = mContext.getResources().openRawResource(
+                R.raw.car_audio_configuration_V1);
+
+        CarAudioZonesHelper cazh = new CarAudioZonesHelper(mContext, versionOneStream,
+                mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
+
+        CarAudioZone[] zones = cazh.loadAudioZones();
+
+        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_forVersionOneWithNonLegacyContexts_throws() {
+        InputStream v1NonLegacyContextStream = mContext.getResources().openRawResource(
+                R.raw.car_audio_configuration_V1_with_non_legacy_contexts);
+
+        CarAudioZonesHelper cazh = new CarAudioZonesHelper(mContext, v1NonLegacyContextStream,
+                mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
+
+        IllegalArgumentException exception = expectThrows(IllegalArgumentException.class,
+                cazh::loadAudioZones);
+
+        assertThat(exception).hasMessageThat().contains("Non-legacy audio contexts such as");
+    }
+
+    @Test
+    public void loadAudioZones_parsesPhysicalDisplayAddresses() throws Exception {
         CarAudioZonesHelper cazh = new CarAudioZonesHelper(mContext, mInputStream,
                 mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
 
@@ -272,8 +304,7 @@
     }
 
     @Test
-    public void loadAudioZones_defaultsDisplayAddressesToEmptyList()
-            throws IOException, XmlPullParserException {
+    public void loadAudioZones_defaultsDisplayAddressesToEmptyList() throws Exception {
         CarAudioZonesHelper cazh = new CarAudioZonesHelper(mContext, mInputStream,
                 mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
 
@@ -285,7 +316,7 @@
     }
 
     @Test(expected = RuntimeException.class)
-    public void loadAudioZones_throwsOnDuplicatePorts() throws IOException, XmlPullParserException {
+    public void loadAudioZones_throwsOnDuplicatePorts() throws Exception {
         try (InputStream duplicatePortStream = mContext.getResources().openRawResource(
                 R.raw.car_audio_configuration_duplicate_ports)) {
             CarAudioZonesHelper cazh = new CarAudioZonesHelper(mContext, duplicatePortStream,
@@ -296,20 +327,15 @@
     }
 
     @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,
-                    mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
+    public void loadAudioZones_throwsOnNonNumericalPort() {
+        InputStream duplicatePortStream = mContext.getResources().openRawResource(
+                R.raw.car_audio_configuration_non_numerical_port);
+        CarAudioZonesHelper cazh = new CarAudioZonesHelper(mContext, duplicatePortStream,
+                mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
 
-            try {
-                cazh.loadAudioZones();
-                fail();
-            } catch (RuntimeException e) {
-                assertEquals(NumberFormatException.class, e.getCause().getClass());
-            }
-        }
+        IllegalArgumentException exception = expectThrows(IllegalArgumentException.class,
+                cazh::loadAudioZones);
+        assertThat(exception).hasMessageThat().contains("Port one is not a number");
     }
 
     @Test
@@ -370,7 +396,7 @@
             assertThat(primaryZoneInputDevices).hasSize(2);
 
             List<String> primaryZoneInputAddresses =
-                    primaryZoneInputDevices.stream().map(a ->a.getAddress()).collect(
+                    primaryZoneInputDevices.stream().map(a -> a.getAddress()).collect(
                             Collectors.toList());
             assertThat(primaryZoneInputAddresses).containsAllOf(PRIMARY_ZONE_FM_TUNER_ADDRESS,
                     PRIMARY_ZONE_MICROPHONE_ADDRESS).inOrder();
@@ -379,7 +405,7 @@
             List<AudioDeviceAttributes> secondaryZoneInputDevices =
                     secondaryZone.getInputAudioDevices();
             List<String> secondaryZoneInputAddresses =
-                    secondaryZoneInputDevices.stream().map(a ->a.getAddress()).collect(
+                    secondaryZoneInputDevices.stream().map(a -> a.getAddress()).collect(
                             Collectors.toList());
             assertThat(secondaryZoneInputAddresses).containsAllOf(
                     SECONDARY_ZONE_BUS_1000_INPUT_ADDRESS,
@@ -413,6 +439,7 @@
             assertThat(thrown).hasMessageThat().contains("already associated with a zone");
         }
     }
+
     @Test
     public void loadAudioZones_failsOnEmptyInputDeviceAddress() throws Exception {
         try (InputStream inputDevicesStream = mContext.getResources().openRawResource(
diff --git a/tests/carservice_unit_test/src/com/android/car/CarOccupantZoneServiceTest.java b/tests/carservice_unit_test/src/com/android/car/CarOccupantZoneServiceTest.java
index 691bdf4..2db5555 100644
--- a/tests/carservice_unit_test/src/com/android/car/CarOccupantZoneServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CarOccupantZoneServiceTest.java
@@ -24,17 +24,20 @@
 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.app.ActivityManager;
 import android.car.Car;
 import android.car.CarOccupantZoneManager;
 import android.car.CarOccupantZoneManager.OccupantZoneInfo;
 import android.car.VehicleAreaSeat;
+import android.car.media.CarAudioManager;
 import android.content.Context;
 import android.content.res.Resources;
 import android.hardware.display.DisplayManager;
 import android.os.Looper;
 import android.os.UserHandle;
+import android.util.SparseIntArray;
 import android.view.Display;
 import android.view.DisplayAddress;
 
@@ -104,6 +107,13 @@
             "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,
@@ -223,6 +233,13 @@
         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() {
@@ -283,6 +300,84 @@
     }
 
     @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();
 
@@ -606,4 +701,29 @@
         mService.mUserCallback.onSwitchUser(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();
+    }
 }
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..a00305f
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioFocusUnitTest.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.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_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_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.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 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;
+
+    private CarAudioFocus mCarAudioFocus;
+
+    @Before
+    public void setUp() {
+        mCarAudioFocus = new CarAudioFocus(mMockAudioManager, mMockPackageManager);
+        mCarAudioFocus.setOwningPolicy(mAudioPolicy);
+    }
+
+    @Test
+    public void onAudioFocusRequest_withNoCurrentFocusHolder_requestGranted() {
+        AudioFocusInfo audioFocusInfo = getInfoForFirstClientWithMedia();
+        mCarAudioFocus.onAudioFocusRequest(audioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager, times(1)).setFocusRequestResult(audioFocusInfo,
+                AUDIOFOCUS_REQUEST_GRANTED, mAudioPolicy);
+    }
+
+    @Test
+    public void onAudioFocusRequest_withSameClientIdSameUsage_requestGranted() {
+        AudioFocusInfo audioFocusInfo = getInfoForFirstClientWithMedia();
+        mCarAudioFocus.onAudioFocusRequest(audioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        AudioFocusInfo sameClientAndUsageFocusInfo = getInfoForFirstClientWithMedia();
+        mCarAudioFocus.onAudioFocusRequest(sameClientAndUsageFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager, times(2)).setFocusRequestResult(sameClientAndUsageFocusInfo,
+                AUDIOFOCUS_REQUEST_GRANTED, mAudioPolicy);
+    }
+
+    @Test
+    public void onAudioFocusRequest_withSameClientIdDifferentUsage_requestFailed() {
+        requestFocusForMediaWithFirstClient();
+
+        AudioFocusInfo sameClientFocusInfo = getInfo(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+                FIRST_CLIENT_ID, AUDIOFOCUS_GAIN);
+        mCarAudioFocus.onAudioFocusRequest(sameClientFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager, times(1)).setFocusRequestResult(sameClientFocusInfo,
+                AUDIOFOCUS_REQUEST_FAILED, mAudioPolicy);
+    }
+
+    @Test
+    public void onAudioFocusRequest_concurrentRequest_requestGranted() {
+        requestFocusForMediaWithFirstClient();
+
+        AudioFocusInfo concurrentFocusInfo = getConcurrentInfo(AUDIOFOCUS_GAIN);
+        mCarAudioFocus.onAudioFocusRequest(concurrentFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager, times(1)).setFocusRequestResult(concurrentFocusInfo,
+                AUDIOFOCUS_REQUEST_GRANTED, mAudioPolicy);
+    }
+
+    @Test
+    public void onAudioFocusRequest_concurrentRequestWithoutDucking_holderLosesFocus() {
+        AudioFocusInfo initialFocusInfo = requestFocusForMediaWithFirstClient();
+
+        AudioFocusInfo concurrentFocusInfo = getConcurrentInfo(AUDIOFOCUS_GAIN);
+        mCarAudioFocus.onAudioFocusRequest(concurrentFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager, times(1)).dispatchAudioFocusChange(initialFocusInfo,
+                AudioManager.AUDIOFOCUS_LOSS, mAudioPolicy);
+    }
+
+    @Test
+    public void onAudioFocusRequest_concurrentRequestMayDuck_holderRetainsFocus() {
+        AudioFocusInfo initialFocusInfo = requestFocusForMediaWithFirstClient();
+
+        AudioFocusInfo concurrentFocusInfo = getConcurrentInfo(AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
+        mCarAudioFocus.onAudioFocusRequest(concurrentFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager, times(0)).dispatchAudioFocusChange(eq(initialFocusInfo),
+                anyInt(), eq(mAudioPolicy));
+    }
+
+    @Test
+    public void onAudioFocusRequest_exclusiveRequest_requestGranted() {
+        requestFocusForMediaWithFirstClient();
+
+        AudioFocusInfo exclusiveRequestInfo = getExclusiveInfo(AUDIOFOCUS_GAIN);
+        mCarAudioFocus.onAudioFocusRequest(exclusiveRequestInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager, times(1)).setFocusRequestResult(exclusiveRequestInfo,
+                AUDIOFOCUS_REQUEST_GRANTED, mAudioPolicy);
+    }
+
+    @Test
+    public void onAudioFocusRequest_exclusiveRequest_holderLosesFocus() {
+        AudioFocusInfo initialFocusInfo = requestFocusForMediaWithFirstClient();
+
+        AudioFocusInfo exclusiveRequestInfo = getExclusiveInfo(AUDIOFOCUS_GAIN);
+        mCarAudioFocus.onAudioFocusRequest(exclusiveRequestInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager, times(1)).dispatchAudioFocusChange(initialFocusInfo,
+                AudioManager.AUDIOFOCUS_LOSS, mAudioPolicy);
+    }
+
+    @Test
+    public void onAudioFocusRequest_exclusiveRequestMayDuck_holderLosesFocusTransiently() {
+        AudioFocusInfo initialFocusInfo = requestFocusForMediaWithFirstClient();
+
+        AudioFocusInfo exclusiveRequestInfo = getExclusiveInfo(AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
+        mCarAudioFocus.onAudioFocusRequest(exclusiveRequestInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager, times(1)).dispatchAudioFocusChange(initialFocusInfo,
+                AudioManager.AUDIOFOCUS_LOSS_TRANSIENT, mAudioPolicy);
+    }
+
+    @Test
+    public void onAudioFocus_rejectRequest_requestFailed() {
+        requestFocusForUsageWithFirstClient(USAGE_ASSISTANT);
+
+        AudioFocusInfo rejectRequestInfo = getRejectInfo();
+        mCarAudioFocus.onAudioFocusRequest(rejectRequestInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager, times(1)).setFocusRequestResult(rejectRequestInfo,
+                AUDIOFOCUS_REQUEST_FAILED, mAudioPolicy);
+    }
+
+    @Test
+    public void onAudioFocus_rejectRequest_holderRetainsFocus() {
+        AudioFocusInfo initialFocusInfo = requestFocusForUsageWithFirstClient(USAGE_ASSISTANT);
+
+        AudioFocusInfo rejectRequestInfo = getRejectInfo();
+        mCarAudioFocus.onAudioFocusRequest(rejectRequestInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager, times(0)).dispatchAudioFocusChange(eq(initialFocusInfo),
+                anyInt(), eq(mAudioPolicy));
+    }
+
+    // System Usage tests
+
+    @Test
+    public void onAudioFocus_exclusiveWithSystemUsage_requestGranted() {
+        requestFocusForMediaWithFirstClient();
+
+        AudioFocusInfo exclusiveSystemUsageInfo = getExclusiveWithSystemUsageInfo();
+        mCarAudioFocus.onAudioFocusRequest(exclusiveSystemUsageInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager, times(1)).setFocusRequestResult(exclusiveSystemUsageInfo,
+                AUDIOFOCUS_REQUEST_GRANTED, mAudioPolicy);
+    }
+
+    @Test
+    public void onAudioFocus_exclusiveWithSystemUsage_holderLosesFocus() {
+        AudioFocusInfo initialFocusInfo = requestFocusForMediaWithFirstClient();
+
+        AudioFocusInfo exclusiveSystemUsageInfo = getExclusiveWithSystemUsageInfo();
+        mCarAudioFocus.onAudioFocusRequest(exclusiveSystemUsageInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager, times(1)).dispatchAudioFocusChange(initialFocusInfo,
+                AUDIOFOCUS_LOSS, mAudioPolicy);
+    }
+
+    @Test
+    public void onAudioFocus_concurrentWithSystemUsage_requestGranted() {
+        requestFocusForMediaWithFirstClient();
+
+        AudioFocusInfo concurrentSystemUsageInfo = getConcurrentWithSystemUsageInfo();
+        mCarAudioFocus.onAudioFocusRequest(concurrentSystemUsageInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager, times(1)).setFocusRequestResult(concurrentSystemUsageInfo,
+                AUDIOFOCUS_REQUEST_GRANTED, mAudioPolicy);
+    }
+
+    @Test
+    public void onAudioFocus_concurrentWithSystemUsageAndConcurrent_holderRetainsFocus() {
+        AudioFocusInfo initialFocusInfo = requestFocusForMediaWithFirstClient();
+
+        AudioFocusInfo concurrentSystemUsageInfo = getConcurrentWithSystemUsageInfo();
+        mCarAudioFocus.onAudioFocusRequest(concurrentSystemUsageInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager, times(0)).dispatchAudioFocusChange(eq(initialFocusInfo),
+                anyInt(), eq(mAudioPolicy));
+    }
+
+    @Test
+    public void onAudioFocus_rejectWithSystemUsage_requestFailed() {
+        requestFocusForUsageWithFirstClient(USAGE_VOICE_COMMUNICATION);
+
+        AudioFocusInfo rejectWithSystemUsageInfo = getRejectWithSystemUsageInfo();
+        mCarAudioFocus.onAudioFocusRequest(rejectWithSystemUsageInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+        verify(mMockAudioManager, times(1)).setFocusRequestResult(rejectWithSystemUsageInfo,
+                AUDIOFOCUS_REQUEST_FAILED, mAudioPolicy);
+    }
+
+    // USAGE_ASSISTANCE_NAVIGATION_GUIDANCE is concurrent with USAGE_MEDIA
+    private AudioFocusInfo getConcurrentInfo(int gainType) {
+        return getInfo(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE, SECOND_CLIENT_ID, gainType);
+    }
+
+    // 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);
+    }
+
+    // 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);
+    }
+
+    // USAGE_ANNOUNCEMENT is rejected with USAGE_VOICE_COMMUNICATION
+    private AudioFocusInfo getRejectWithSystemUsageInfo() {
+        return getSystemUsageInfo(USAGE_ANNOUNCEMENT, AUDIOFOCUS_GAIN);
+    }
+
+    private AudioFocusInfo requestFocusForUsageWithFirstClient(@AttributeUsage int usage) {
+        AudioFocusInfo initialFocusInfo = getInfo(usage, FIRST_CLIENT_ID, AUDIOFOCUS_GAIN);
+        mCarAudioFocus.onAudioFocusRequest(initialFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+        return initialFocusInfo;
+    }
+
+    private AudioFocusInfo requestFocusForMediaWithFirstClient() {
+        return requestFocusForUsageWithFirstClient(USAGE_MEDIA);
+    }
+
+    private AudioFocusInfo getInfoForFirstClientWithMedia() {
+        return getInfo(USAGE_MEDIA, FIRST_CLIENT_ID, AUDIOFOCUS_GAIN);
+    }
+
+    private AudioFocusInfo getInfo(@AttributeUsage int usage, String clientId, int gainType) {
+        AudioAttributes audioAttributes = new AudioAttributes.Builder()
+                .setUsage(usage)
+                .build();
+        return getInfo(audioAttributes, clientId, gainType);
+    }
+
+    private AudioFocusInfo getSystemUsageInfo(@AttributeUsage int systemUsage, int gainType) {
+        AudioAttributes audioAttributes = new AudioAttributes.Builder()
+                .setSystemUsage(systemUsage)
+                .build();
+        return getInfo(audioAttributes, SECOND_CLIENT_ID, gainType);
+    }
+
+    private AudioFocusInfo getInfo(AudioAttributes audioAttributes, String clientId, int gainType) {
+        return new AudioFocusInfo(audioAttributes, CLIENT_UID, clientId, PACKAGE_NAME,
+                gainType, AudioManager.AUDIOFOCUS_NONE,
+                AUDIOFOCUS_FLAG, Build.VERSION.SDK_INT);
+    }
+}
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 3d6bcc3..8333a21 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
@@ -27,6 +27,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.hardware.automotive.vehicle.V2_0.RotaryInputType;
 import android.hardware.automotive.vehicle.V2_0.VehicleHwKeyInputAction;
 import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
@@ -62,6 +63,8 @@
 
     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 }
@@ -104,6 +107,38 @@
 
         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());
+
+        Collection<VehiclePropConfig> takenProps =
+                mInputHalService.takeSupportedProperties(offeredProps);
+
+        assertThat(takenProps).containsExactly(HW_ROTARY_INPUT_CONFIG);
+        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());
+
+        Collection<VehiclePropConfig> takenProps =
+                mInputHalService.takeSupportedProperties(offeredProps);
+
+        assertThat(takenProps).containsExactly(HW_KEY_INPUT_CONFIG, HW_ROTARY_INPUT_CONFIG);
+        assertThat(mInputHalService.isKeyInputSupported()).isTrue();
+        assertThat(mInputHalService.isRotaryInputSupported()).isTrue();
     }
 
     @Test
@@ -228,6 +263,72 @@
         assertThat(event.getRepeatCount()).isEqualTo(0);
     }
 
+    @Test
+    public void dispatchesRotaryEvent_singleVolumeUp_toListener() {
+        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() {
+        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));
         assertThat(mInputHalService.isKeyInputSupported()).isTrue();
@@ -278,4 +379,18 @@
         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/UserHalServiceTest.java b/tests/carservice_unit_test/src/com/android/car/hal/UserHalServiceTest.java
index d5f4ccc..1a07456 100644
--- a/tests/carservice_unit_test/src/com/android/car/hal/UserHalServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/hal/UserHalServiceTest.java
@@ -217,7 +217,7 @@
 
     @Test
     public void testGetUserInfo_halReplyWithWrongRequestId() throws Exception {
-        // TODO(b/146207078): use helper method to convert prop value to proper req
+        // TODO(b/150419600): use helper method to convert prop value to proper req
         VehiclePropValue propResponse = new VehiclePropValue();
         propResponse.prop = INITIAL_USER_INFO;
         propResponse.value.int32Values.add(REQUEST_ID_PLACE_HOLDER);
@@ -237,7 +237,7 @@
 
     @Test
     public void testGetUserInfo_halReturnedInvalidAction() throws Exception {
-        // TODO(b/146207078): use helper method to convert prop value to proper req
+        // TODO(b/150419600): use helper method to convert prop value to proper req
         VehiclePropValue propResponse = new VehiclePropValue();
         propResponse.prop = INITIAL_USER_INFO;
         propResponse.value.int32Values.add(REQUEST_ID_PLACE_HOLDER);
@@ -263,7 +263,7 @@
 
     @Test
     public void testGetUserInfo_successDefault() throws Exception {
-        // TODO(b/146207078): use helper method to convert prop value to proper req
+        // TODO(b/150419600): use helper method to convert prop value to proper req
         VehiclePropValue propResponse = new VehiclePropValue();
         propResponse.prop = INITIAL_USER_INFO;
         propResponse.value.int32Values.add(REQUEST_ID_PLACE_HOLDER);
@@ -295,7 +295,7 @@
     @Test
     public void testGetUserInfo_successSwitchUser() throws Exception {
         int userIdToSwitch = 42;
-        // TODO(b/146207078): use helper method to convert prop value to proper req
+        // TODO(b/150419600): use helper method to convert prop value to proper req
         VehiclePropValue propResponse = new VehiclePropValue();
         propResponse.prop = INITIAL_USER_INFO;
         propResponse.value.int32Values.add(REQUEST_ID_PLACE_HOLDER);
@@ -329,7 +329,7 @@
     public void testGetUserInfo_successCreateUser() throws Exception {
         int newUserFlags = 108;
         String newUserName = "Groot";
-        // TODO(b/146207078): use helper method to convert prop value to proper req
+        // TODO(b/150419600): use helper method to convert prop value to proper req
         VehiclePropValue propResponse = new VehiclePropValue();
         propResponse.prop = INITIAL_USER_INFO;
         propResponse.value.int32Values.add(REQUEST_ID_PLACE_HOLDER);
@@ -369,7 +369,7 @@
      * @param initialIndex first index of the info values in the property's {@code int32Values}
      */
     private void assertUsersInfo(VehiclePropValue value, UsersInfo info, int initialIndex) {
-        // TODO(b/146207078): use helper method to convert prop value to proper req to check users
+        // TODO(b/150419600): use helper method to convert prop value to proper req to check users
         ArrayList<Integer> values = value.value.int32Values;
         assertWithMessage("wrong values size").that(values)
                 .hasSize(initialIndex + 3 + info.numberUsers * 2);
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 128dfcb..48fa261 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
@@ -594,7 +594,9 @@
         mCarUserService.getInitialUserInfo(mGetUserInfoRequestType, mAsyncCallTimeoutMs, mReceiver);
 
         assertThat(mReceiver.getResultCode()).isEqualTo(HalCallback.STATUS_OK);
-        assertThat(mReceiver.getResultData()).isNull();
+        Bundle resultData = mReceiver.getResultData();
+        assertThat(resultData).isNotNull();
+        assertInitialInfoAction(resultData, mGetUserInfoResponse.action);
     }
 
     @Test
@@ -617,7 +619,6 @@
         assertNoUserName(resultData);
     }
 
-
     @Test
     public void testGetUserInfo_createUserResponse() throws Exception {
         int newUserFlags = 42;