Merge "Refactor audio device type in audio frameworks."
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index a3a8777..d64e4ef 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -30,7 +30,9 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 
 /* IF YOU CHANGE ANY OF THE CONSTANTS IN THIS FILE, DO NOT FORGET
  * TO UPDATE THE CORRESPONDING NATIVE GLUE AND AudioManager.java.
@@ -543,51 +545,75 @@
 
     public static final int DEVICE_OUT_DEFAULT = DEVICE_BIT_DEFAULT;
 
-    public static final int DEVICE_OUT_ALL = (DEVICE_OUT_EARPIECE |
-                                              DEVICE_OUT_SPEAKER |
-                                              DEVICE_OUT_WIRED_HEADSET |
-                                              DEVICE_OUT_WIRED_HEADPHONE |
-                                              DEVICE_OUT_BLUETOOTH_SCO |
-                                              DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
-                                              DEVICE_OUT_BLUETOOTH_SCO_CARKIT |
-                                              DEVICE_OUT_BLUETOOTH_A2DP |
-                                              DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
-                                              DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER |
-                                              DEVICE_OUT_HDMI |
-                                              DEVICE_OUT_ANLG_DOCK_HEADSET |
-                                              DEVICE_OUT_DGTL_DOCK_HEADSET |
-                                              DEVICE_OUT_USB_ACCESSORY |
-                                              DEVICE_OUT_USB_DEVICE |
-                                              DEVICE_OUT_REMOTE_SUBMIX |
-                                              DEVICE_OUT_TELEPHONY_TX |
-                                              DEVICE_OUT_LINE |
-                                              DEVICE_OUT_HDMI_ARC |
-                                              DEVICE_OUT_SPDIF |
-                                              DEVICE_OUT_FM |
-                                              DEVICE_OUT_AUX_LINE |
-                                              DEVICE_OUT_SPEAKER_SAFE |
-                                              DEVICE_OUT_IP |
-                                              DEVICE_OUT_BUS |
-                                              DEVICE_OUT_PROXY |
-                                              DEVICE_OUT_USB_HEADSET |
-                                              DEVICE_OUT_HEARING_AID |
-                                              DEVICE_OUT_DEFAULT);
-    public static final int DEVICE_OUT_ALL_A2DP = (DEVICE_OUT_BLUETOOTH_A2DP |
-                                                   DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
-                                                   DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER);
-    public static final int DEVICE_OUT_ALL_SCO = (DEVICE_OUT_BLUETOOTH_SCO |
-                                                  DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
-                                                  DEVICE_OUT_BLUETOOTH_SCO_CARKIT);
+    // Deprecated in R because multiple device types are no longer accessed as a bit mask.
+    // Removing this will get lint warning about changing hidden apis.
     @UnsupportedAppUsage
     public static final int DEVICE_OUT_ALL_USB = (DEVICE_OUT_USB_ACCESSORY |
                                                   DEVICE_OUT_USB_DEVICE |
                                                   DEVICE_OUT_USB_HEADSET);
-    public static final int DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO = (DEVICE_OUT_AUX_LINE |
-                                                                DEVICE_OUT_HDMI_ARC |
-                                                                DEVICE_OUT_SPDIF);
-    public static final int DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER =
-            (DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO |
-             DEVICE_OUT_SPEAKER);
+
+    public static final Set<Integer> DEVICE_OUT_ALL_SET;
+    public static final Set<Integer> DEVICE_OUT_ALL_A2DP_SET;
+    public static final Set<Integer> DEVICE_OUT_ALL_SCO_SET;
+    public static final Set<Integer> DEVICE_OUT_ALL_USB_SET;
+    public static final Set<Integer> DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET;
+    public static final Set<Integer> DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET;
+    static {
+        DEVICE_OUT_ALL_SET = new HashSet<>();
+        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_EARPIECE);
+        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_SPEAKER);
+        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_WIRED_HEADSET);
+        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_WIRED_HEADPHONE);
+        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLUETOOTH_SCO);
+        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLUETOOTH_SCO_HEADSET);
+        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLUETOOTH_SCO_CARKIT);
+        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLUETOOTH_A2DP);
+        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES);
+        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER);
+        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_HDMI);
+        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_ANLG_DOCK_HEADSET);
+        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_DGTL_DOCK_HEADSET);
+        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_USB_ACCESSORY);
+        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_USB_DEVICE);
+        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_REMOTE_SUBMIX);
+        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_TELEPHONY_TX);
+        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_LINE);
+        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_HDMI_ARC);
+        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_SPDIF);
+        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_FM);
+        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_AUX_LINE);
+        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_SPEAKER_SAFE);
+        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_IP);
+        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BUS);
+        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_PROXY);
+        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_USB_HEADSET);
+        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_HEARING_AID);
+        DEVICE_OUT_ALL_SET.add(DEVICE_OUT_DEFAULT);
+
+        DEVICE_OUT_ALL_A2DP_SET = new HashSet<>();
+        DEVICE_OUT_ALL_A2DP_SET.add(DEVICE_OUT_BLUETOOTH_A2DP);
+        DEVICE_OUT_ALL_A2DP_SET.add(DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES);
+        DEVICE_OUT_ALL_A2DP_SET.add(DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER);
+
+        DEVICE_OUT_ALL_SCO_SET = new HashSet<>();
+        DEVICE_OUT_ALL_SCO_SET.add(DEVICE_OUT_BLUETOOTH_SCO);
+        DEVICE_OUT_ALL_SCO_SET.add(DEVICE_OUT_BLUETOOTH_SCO_HEADSET);
+        DEVICE_OUT_ALL_SCO_SET.add(DEVICE_OUT_BLUETOOTH_SCO_CARKIT);
+
+        DEVICE_OUT_ALL_USB_SET = new HashSet<>();
+        DEVICE_OUT_ALL_USB_SET.add(DEVICE_OUT_USB_ACCESSORY);
+        DEVICE_OUT_ALL_USB_SET.add(DEVICE_OUT_USB_DEVICE);
+        DEVICE_OUT_ALL_USB_SET.add(DEVICE_OUT_USB_HEADSET);
+
+        DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET = new HashSet<>();
+        DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET.add(DEVICE_OUT_AUX_LINE);
+        DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET.add(DEVICE_OUT_HDMI_ARC);
+        DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET.add(DEVICE_OUT_SPDIF);
+
+        DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET = new HashSet<>();
+        DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET.addAll(DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET);
+        DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET.add(DEVICE_OUT_SPEAKER);
+    }
 
     // input devices
     @UnsupportedAppUsage
@@ -635,37 +661,47 @@
     @UnsupportedAppUsage
     public static final int DEVICE_IN_DEFAULT = DEVICE_BIT_IN | DEVICE_BIT_DEFAULT;
 
-    public static final int DEVICE_IN_ALL = (DEVICE_IN_COMMUNICATION |
-                                             DEVICE_IN_AMBIENT |
-                                             DEVICE_IN_BUILTIN_MIC |
-                                             DEVICE_IN_BLUETOOTH_SCO_HEADSET |
-                                             DEVICE_IN_WIRED_HEADSET |
-                                             DEVICE_IN_HDMI |
-                                             DEVICE_IN_TELEPHONY_RX |
-                                             DEVICE_IN_BACK_MIC |
-                                             DEVICE_IN_REMOTE_SUBMIX |
-                                             DEVICE_IN_ANLG_DOCK_HEADSET |
-                                             DEVICE_IN_DGTL_DOCK_HEADSET |
-                                             DEVICE_IN_USB_ACCESSORY |
-                                             DEVICE_IN_USB_DEVICE |
-                                             DEVICE_IN_FM_TUNER |
-                                             DEVICE_IN_TV_TUNER |
-                                             DEVICE_IN_LINE |
-                                             DEVICE_IN_SPDIF |
-                                             DEVICE_IN_BLUETOOTH_A2DP |
-                                             DEVICE_IN_LOOPBACK |
-                                             DEVICE_IN_IP |
-                                             DEVICE_IN_BUS |
-                                             DEVICE_IN_PROXY |
-                                             DEVICE_IN_USB_HEADSET |
-                                             DEVICE_IN_BLUETOOTH_BLE |
-                                             DEVICE_IN_HDMI_ARC |
-                                             DEVICE_IN_ECHO_REFERENCE |
-                                             DEVICE_IN_DEFAULT);
-    public static final int DEVICE_IN_ALL_SCO = DEVICE_IN_BLUETOOTH_SCO_HEADSET;
-    public static final int DEVICE_IN_ALL_USB = (DEVICE_IN_USB_ACCESSORY |
-                                                 DEVICE_IN_USB_DEVICE |
-                                                 DEVICE_IN_USB_HEADSET);
+    public static final Set<Integer> DEVICE_IN_ALL_SET;
+    public static final Set<Integer> DEVICE_IN_ALL_SCO_SET;
+    public static final Set<Integer> DEVICE_IN_ALL_USB_SET;
+    static {
+        DEVICE_IN_ALL_SET = new HashSet<>();
+        DEVICE_IN_ALL_SET.add(DEVICE_IN_COMMUNICATION);
+        DEVICE_IN_ALL_SET.add(DEVICE_IN_AMBIENT);
+        DEVICE_IN_ALL_SET.add(DEVICE_IN_BUILTIN_MIC);
+        DEVICE_IN_ALL_SET.add(DEVICE_IN_BLUETOOTH_SCO_HEADSET);
+        DEVICE_IN_ALL_SET.add(DEVICE_IN_WIRED_HEADSET);
+        DEVICE_IN_ALL_SET.add(DEVICE_IN_HDMI);
+        DEVICE_IN_ALL_SET.add(DEVICE_IN_TELEPHONY_RX);
+        DEVICE_IN_ALL_SET.add(DEVICE_IN_BACK_MIC);
+        DEVICE_IN_ALL_SET.add(DEVICE_IN_REMOTE_SUBMIX);
+        DEVICE_IN_ALL_SET.add(DEVICE_IN_ANLG_DOCK_HEADSET);
+        DEVICE_IN_ALL_SET.add(DEVICE_IN_DGTL_DOCK_HEADSET);
+        DEVICE_IN_ALL_SET.add(DEVICE_IN_USB_ACCESSORY);
+        DEVICE_IN_ALL_SET.add(DEVICE_IN_USB_DEVICE);
+        DEVICE_IN_ALL_SET.add(DEVICE_IN_FM_TUNER);
+        DEVICE_IN_ALL_SET.add(DEVICE_IN_TV_TUNER);
+        DEVICE_IN_ALL_SET.add(DEVICE_IN_LINE);
+        DEVICE_IN_ALL_SET.add(DEVICE_IN_SPDIF);
+        DEVICE_IN_ALL_SET.add(DEVICE_IN_BLUETOOTH_A2DP);
+        DEVICE_IN_ALL_SET.add(DEVICE_IN_LOOPBACK);
+        DEVICE_IN_ALL_SET.add(DEVICE_IN_IP);
+        DEVICE_IN_ALL_SET.add(DEVICE_IN_BUS);
+        DEVICE_IN_ALL_SET.add(DEVICE_IN_PROXY);
+        DEVICE_IN_ALL_SET.add(DEVICE_IN_USB_HEADSET);
+        DEVICE_IN_ALL_SET.add(DEVICE_IN_BLUETOOTH_BLE);
+        DEVICE_IN_ALL_SET.add(DEVICE_IN_HDMI_ARC);
+        DEVICE_IN_ALL_SET.add(DEVICE_IN_ECHO_REFERENCE);
+        DEVICE_IN_ALL_SET.add(DEVICE_IN_DEFAULT);
+
+        DEVICE_IN_ALL_SCO_SET = new HashSet<>();
+        DEVICE_IN_ALL_SCO_SET.add(DEVICE_IN_BLUETOOTH_SCO_HEADSET);
+
+        DEVICE_IN_ALL_USB_SET = new HashSet<>();
+        DEVICE_IN_ALL_USB_SET.add(DEVICE_IN_USB_ACCESSORY);
+        DEVICE_IN_ALL_USB_SET.add(DEVICE_IN_USB_DEVICE);
+        DEVICE_IN_ALL_USB_SET.add(DEVICE_IN_USB_HEADSET);
+    }
 
     // device states, must match AudioSystem::device_connection_state
     @UnsupportedAppUsage
@@ -1229,6 +1265,40 @@
         return getPlatformType(context) == PLATFORM_TELEVISION || forceSingleVolume;
     }
 
+    /**
+     * Return a set of audio device types from a bit mask audio device type, which may
+     * represent multiple audio device types.
+     * FIXME: Remove this when getting ride of bit mask usage of audio device types.
+     */
+    public static Set<Integer> generateAudioDeviceTypesSet(int types) {
+        Set<Integer> deviceTypes = new HashSet<>();
+        Set<Integer> allDeviceTypes =
+                (types & DEVICE_BIT_IN) == 0 ? DEVICE_OUT_ALL_SET : DEVICE_IN_ALL_SET;
+        for (int deviceType : allDeviceTypes) {
+            if ((types & deviceType) == deviceType) {
+                deviceTypes.add(deviceType);
+            }
+        }
+        return deviceTypes;
+    }
+
+    /**
+     * Return the intersection of two audio device types collections.
+     */
+    public static Set<Integer> intersectionAudioDeviceTypes(
+            @NonNull Set<Integer> a, @NonNull Set<Integer> b) {
+        Set<Integer> intersection = new HashSet<>(a);
+        intersection.retainAll(b);
+        return intersection;
+    }
+
+    /**
+     * Return true if the audio device types collection only contains the given device type.
+     */
+    public static boolean isSingleAudioDeviceType(@NonNull Set<Integer> types, int type) {
+        return types.size() == 1 && types.contains(type);
+    }
+
     public static final int DEFAULT_MUTE_STREAMS_AFFECTED =
             (1 << STREAM_MUSIC) |
             (1 << STREAM_RING) |
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 90973a8..a2b3574 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -44,6 +44,8 @@
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
 
 /**
  * Class to manage the inventory of all connected devices.
@@ -372,9 +374,14 @@
         mDeviceBroker.postObserveDevicesForAllStreams();
     }
 
-    private static final int DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG =
-            AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE
-                    | AudioSystem.DEVICE_OUT_LINE | AudioSystem.DEVICE_OUT_ALL_USB;
+    private static final Set<Integer> DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET;
+    static {
+        DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET = new HashSet<>();
+        DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_WIRED_HEADSET);
+        DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE);
+        DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_LINE);
+        DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.addAll(AudioSystem.DEVICE_OUT_ALL_USB_SET);
+    }
 
     /*package*/ void onSetWiredDeviceConnectionState(
                             AudioDeviceInventory.WiredDeviceConnectionState wdcs) {
@@ -382,7 +389,7 @@
 
         synchronized (mConnectedDevices) {
             if ((wdcs.mState == AudioService.CONNECTION_STATE_DISCONNECTED)
-                    && ((wdcs.mType & DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG) != 0)) {
+                    && DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.contains(wdcs.mType)) {
                 mDeviceBroker.setBluetoothA2dpOnInt(true,
                         "onSetWiredDeviceConnectionState state DISCONNECTED");
             }
@@ -393,7 +400,7 @@
                 return;
             }
             if (wdcs.mState != AudioService.CONNECTION_STATE_DISCONNECTED) {
-                if ((wdcs.mType & DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG) != 0) {
+                if (DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.contains(wdcs.mType)) {
                     mDeviceBroker.setBluetoothA2dpOnInt(false,
                             "onSetWiredDeviceConnectionState state not DISCONNECTED");
                 }
@@ -764,13 +771,19 @@
     // - none of these devices are connected anymore after one is disconnected AND
     // - the device being disconnected is actually used for music.
     // Access synchronized on mConnectedDevices
-    private int mBecomingNoisyIntentDevices =
-            AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE
-                    | AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI
-                    | AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET
-                    | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET
-                    | AudioSystem.DEVICE_OUT_ALL_USB | AudioSystem.DEVICE_OUT_LINE
-                    | AudioSystem.DEVICE_OUT_HEARING_AID;
+    private static final Set<Integer> BECOMING_NOISY_INTENT_DEVICES_SET;
+    static {
+        BECOMING_NOISY_INTENT_DEVICES_SET = new HashSet<>();
+        BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_WIRED_HEADSET);
+        BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE);
+        BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_HDMI);
+        BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET);
+        BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET);
+        BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_LINE);
+        BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_HEARING_AID);
+        BECOMING_NOISY_INTENT_DEVICES_SET.addAll(AudioSystem.DEVICE_OUT_ALL_A2DP_SET);
+        BECOMING_NOISY_INTENT_DEVICES_SET.addAll(AudioSystem.DEVICE_OUT_ALL_USB_SET);
+    }
 
     // must be called before removing the device from mConnectedDevices
     // musicDevice argument is used when not AudioSystem.DEVICE_NONE instead of querying
@@ -781,16 +794,16 @@
         if (state != AudioService.CONNECTION_STATE_DISCONNECTED) {
             return 0;
         }
-        if ((device & mBecomingNoisyIntentDevices) == 0) {
+        if (!BECOMING_NOISY_INTENT_DEVICES_SET.contains(device)) {
             return 0;
         }
         int delay = 0;
-        int devices = 0;
+        Set<Integer> devices = new HashSet<>();
         for (int i = 0; i < mConnectedDevices.size(); i++) {
             int dev = mConnectedDevices.valueAt(i).mDeviceType;
             if (((dev & AudioSystem.DEVICE_BIT_IN) == 0)
-                    && ((dev & mBecomingNoisyIntentDevices) != 0)) {
-                devices |= dev;
+                    && BECOMING_NOISY_INTENT_DEVICES_SET.contains(dev)) {
+                devices.add(dev);
             }
         }
         if (musicDevice == AudioSystem.DEVICE_NONE) {
@@ -801,8 +814,9 @@
         // because music routing is altered in this case.
         // also checks whether media routing if affected by a dynamic policy or mirroring
         if (((device == musicDevice) || mDeviceBroker.isInCommunication())
-                && (device == devices) && !mDeviceBroker.hasMediaDynamicPolicy()
-                        && ((musicDevice & AudioSystem.DEVICE_OUT_REMOTE_SUBMIX) == 0)) {
+                && AudioSystem.isSingleAudioDeviceType(devices, device)
+                && !mDeviceBroker.hasMediaDynamicPolicy()
+                && (musicDevice != AudioSystem.DEVICE_OUT_REMOTE_SUBMIX)) {
             if (!AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0 /*not looking in past*/)
                     && !mDeviceBroker.hasAudioFocusUsers()) {
                 // no media playback, not a "becoming noisy" situation, otherwise it could cause
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 9a92778..e426c6c 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -147,6 +147,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -501,18 +502,20 @@
     private volatile IRingtonePlayer mRingtonePlayer;
 
     // Devices for which the volume is fixed (volume is either max or muted)
-    int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
-            AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
-            AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET |
-            AudioSystem.DEVICE_OUT_HDMI_ARC |
-            AudioSystem.DEVICE_OUT_SPDIF |
-            AudioSystem.DEVICE_OUT_AUX_LINE;
+    Set<Integer> mFixedVolumeDevices = new HashSet<>(Arrays.asList(
+            AudioSystem.DEVICE_OUT_HDMI,
+            AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET,
+            AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET,
+            AudioSystem.DEVICE_OUT_HDMI_ARC,
+            AudioSystem.DEVICE_OUT_SPDIF,
+            AudioSystem.DEVICE_OUT_AUX_LINE));
     // Devices for which the volume is always max, no volume panel
-    int mFullVolumeDevices = 0;
+    Set<Integer> mFullVolumeDevices = new HashSet<>();
     // Devices for the which use the "absolute volume" concept (framework sends audio signal
     // full scale, and volume control separately) and can be used for multiple use cases reflected
     // by the audio mode (e.g. media playback in MODE_NORMAL, and phone calls in MODE_IN_CALL).
-    int mAbsVolumeMultiModeCaseDevices = AudioSystem.DEVICE_OUT_HEARING_AID;
+    Set<Integer> mAbsVolumeMultiModeCaseDevices = new HashSet<>(
+            Arrays.asList(AudioSystem.DEVICE_OUT_HEARING_AID));
 
     private final boolean mMonitorRotation;
 
@@ -866,13 +869,14 @@
                 }
                 mHdmiTvClient = mHdmiManager.getTvClient();
                 if (mHdmiTvClient != null) {
-                    mFixedVolumeDevices &= ~AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER;
+                    mFixedVolumeDevices.removeAll(
+                            AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET);
                 }
                 mHdmiPlaybackClient = mHdmiManager.getPlaybackClient();
                 if (mHdmiPlaybackClient != null) {
                     // not a television: HDMI output will be always at max
-                    mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
-                    mFullVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
+                    mFixedVolumeDevices.remove(AudioSystem.DEVICE_OUT_HDMI);
+                    mFullVolumeDevices.add(AudioSystem.DEVICE_OUT_HDMI);
                 }
                 mHdmiAudioSystemClient = mHdmiManager.getAudioSystemClient();
             }
@@ -1131,7 +1135,7 @@
             @AudioService.ConnectionState int state, String caller) {
         if (state == AudioService.CONNECTION_STATE_CONNECTED) {
             // DEVICE_OUT_HDMI is now connected
-            if ((AudioSystem.DEVICE_OUT_HDMI & mSafeMediaVolumeDevices) != 0) {
+            if (mSafeMediaVolumeDevices.contains(AudioSystem.DEVICE_OUT_HDMI)) {
                 sendMsg(mAudioHandler,
                         MSG_CHECK_MUSIC_ACTIVE,
                         SENDMSG_REPLACE,
@@ -1762,8 +1766,8 @@
 
         // skip a2dp absolute volume control request when the device
         // is not an a2dp device
-        if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
-            (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
+        if (!AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
+                && (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
             return;
         }
 
@@ -1784,14 +1788,14 @@
 
         flags &= ~AudioManager.FLAG_FIXED_VOLUME;
         if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
-                ((device & mFixedVolumeDevices) != 0)) {
+                mFixedVolumeDevices.contains(device)) {
             flags |= AudioManager.FLAG_FIXED_VOLUME;
 
             // Always toggle between max safe volume and 0 for fixed volume devices where safe
             // volume is enforced, and max and 0 for the others.
             // This is simulated by stepping by the full allowed volume range
             if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
-                    (device & mSafeMediaVolumeDevices) != 0) {
+                    mSafeMediaVolumeDevices.contains(device)) {
                 step = safeMediaVolumeIndex(device);
             } else {
                 step = streamState.getMaxIndex();
@@ -1861,7 +1865,7 @@
                     !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
                 Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex);
                 mVolumeController.postDisplaySafeVolumeWarning(flags);
-            } else if (((device & mFullVolumeDevices) == 0)
+            } else if (!mFullVolumeDevices.contains(device)
                     && (streamState.adjustIndex(direction * step, device, caller)
                             || streamState.mIsMuted)) {
                 // Post message to set system volume (it in turn will post a
@@ -1890,9 +1894,9 @@
             int newIndex = mStreamStates[streamType].getIndex(device);
 
             // Check if volume update should be send to AVRCP
-            if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
-                (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
-                (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
+            if (streamTypeAlias == AudioSystem.STREAM_MUSIC
+                    && AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
+                    && (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
                 if (DEBUG_VOL) {
                     Log.d(TAG, "adjustSreamVolume: postSetAvrcpAbsoluteVolumeIndex index="
                             + newIndex + "stream=" + streamType);
@@ -1901,7 +1905,7 @@
             }
 
             // Check if volume update should be send to Hearing Aid
-            if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0) {
+            if (device == AudioSystem.DEVICE_OUT_HEARING_AID) {
                 // only modify the hearing aid attenuation when the stream to modify matches
                 // the one expected by the hearing aid
                 if (streamType == getHearingAidStreamType()) {
@@ -1923,7 +1927,7 @@
                     if (mHdmiCecSink
                             && streamTypeAlias == AudioSystem.STREAM_MUSIC
                             // vol change on a full volume device
-                            && ((device & mFullVolumeDevices) != 0)) {
+                            && mFullVolumeDevices.contains(device)) {
                         int keyCode = KeyEvent.KEYCODE_UNKNOWN;
                         switch (direction) {
                             case AudioManager.ADJUST_RAISE:
@@ -2291,13 +2295,17 @@
 
         int streamType = getHearingAidStreamType(newMode);
 
-        final int device = AudioSystem.getDevicesForStream(streamType);
-        if ((device & mAbsVolumeMultiModeCaseDevices) == 0) {
+        final Set<Integer> deviceTypes = AudioSystem.generateAudioDeviceTypesSet(
+                AudioSystem.getDevicesForStream(streamType));
+        final Set<Integer> absVolumeMultiModeCaseDevices = AudioSystem.intersectionAudioDeviceTypes(
+                mAbsVolumeMultiModeCaseDevices, deviceTypes);
+        if (absVolumeMultiModeCaseDevices.isEmpty()) {
             return;
         }
 
         // handling of specific interfaces goes here:
-        if ((device & mAbsVolumeMultiModeCaseDevices) == AudioSystem.DEVICE_OUT_HEARING_AID) {
+        if (AudioSystem.isSingleAudioDeviceType(
+                absVolumeMultiModeCaseDevices, AudioSystem.DEVICE_OUT_HEARING_AID)) {
             final int index = getStreamVolume(streamType);
             sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_MODE_CHANGE_HEARING_AID,
                     newMode, streamType, index));
@@ -2324,8 +2332,8 @@
 
         // skip a2dp absolute volume control request when the device
         // is not an a2dp device
-        if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
-            (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
+        if (!AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
+                && (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
             return;
         }
         // If we are being called by the system (e.g. hardware keys) check for current user
@@ -2357,7 +2365,7 @@
             index = rescaleIndex(index * 10, streamType, streamTypeAlias);
 
             if (streamTypeAlias == AudioSystem.STREAM_MUSIC
-                    && (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0
+                    && AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
                     && (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
                 if (DEBUG_VOL) {
                     Log.d(TAG, "setStreamVolume postSetAvrcpAbsoluteVolumeIndex index=" + index
@@ -2366,7 +2374,7 @@
                 mDeviceBroker.postSetAvrcpAbsoluteVolumeIndex(index / 10);
             }
 
-            if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0
+            if (device == AudioSystem.DEVICE_OUT_HEARING_AID
                     && streamType == getHearingAidStreamType()) {
                 Log.i(TAG, "setStreamVolume postSetHearingAidVolumeIndex index=" + index
                         + " stream=" + streamType);
@@ -2379,13 +2387,13 @@
 
             flags &= ~AudioManager.FLAG_FIXED_VOLUME;
             if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
-                    ((device & mFixedVolumeDevices) != 0)) {
+                    mFixedVolumeDevices.contains(device)) {
                 flags |= AudioManager.FLAG_FIXED_VOLUME;
 
                 // volume is either 0 or max allowed for fixed volume devices
                 if (index != 0) {
                     if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
-                            (device & mSafeMediaVolumeDevices) != 0) {
+                            mSafeMediaVolumeDevices.contains(device)) {
                         index = safeMediaVolumeIndex(device);
                     } else {
                         index = streamState.getMaxIndex();
@@ -2568,7 +2576,7 @@
 
         if (streamType == AudioSystem.STREAM_MUSIC) {
             flags = updateFlagsForTvPlatform(flags);
-            if ((device & mFullVolumeDevices) != 0) {
+            if (mFullVolumeDevices.contains(device)) {
                 flags &= ~AudioManager.FLAG_SHOW_UI;
             }
         }
@@ -2614,7 +2622,7 @@
                                     int device,
                                     boolean force,
                                     String caller) {
-        if ((device & mFullVolumeDevices) != 0) {
+        if (mFullVolumeDevices.contains(device)) {
             return;
         }
         VolumeStreamState streamState = mStreamStates[streamType];
@@ -2731,8 +2739,8 @@
                 if (!hasRmtSbmxFullVolDeathHandlerFor(cb)) {
                     mRmtSbmxFullVolDeathHandlers.add(new RmtSbmxFullVolDeathHandler(cb));
                     if (mRmtSbmxFullVolRefCount == 0) {
-                        mFullVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
-                        mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
+                        mFullVolumeDevices.add(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX);
+                        mFixedVolumeDevices.add(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX);
                         applyRequired = true;
                     }
                     mRmtSbmxFullVolRefCount++;
@@ -2741,8 +2749,8 @@
                 if (discardRmtSbmxFullVolDeathHandlerFor(cb) && (mRmtSbmxFullVolRefCount > 0)) {
                     mRmtSbmxFullVolRefCount--;
                     if (mRmtSbmxFullVolRefCount == 0) {
-                        mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
-                        mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
+                        mFullVolumeDevices.remove(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX);
+                        mFixedVolumeDevices.remove(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX);
                         applyRequired = true;
                     }
                 }
@@ -2824,7 +2832,7 @@
                 index = 0;
             }
             if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
-                    (device & mFixedVolumeDevices) != 0) {
+                    mFixedVolumeDevices.contains(device)) {
                 index = mStreamStates[streamType].getMaxIndex();
             }
             return (index + 5) / 10;
@@ -3699,7 +3707,7 @@
             if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
                 int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
 
-                if ((device & mSafeMediaVolumeDevices) != 0) {
+                if (mSafeMediaVolumeDevices.contains(device)) {
                     sendMsg(mAudioHandler,
                             MSG_CHECK_MUSIC_ACTIVE,
                             SENDMSG_REPLACE,
@@ -4251,6 +4259,8 @@
             // retain the device on the A2DP output as the other must not correspond to an active
             // selection if not the speaker.
             //  - HDMI-CEC system audio mode only output: give priority to available item in order.
+            // FIXME: Haven't applied audio device type refactor to this API
+            //  as it is going to be deprecated.
             if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
                 device = AudioSystem.DEVICE_OUT_SPEAKER;
             } else if ((device & AudioSystem.DEVICE_OUT_HDMI_ARC) != 0) {
@@ -4260,7 +4270,11 @@
             } else if ((device & AudioSystem.DEVICE_OUT_AUX_LINE) != 0) {
                 device = AudioSystem.DEVICE_OUT_AUX_LINE;
             } else {
-                device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
+                for (int deviceType : AudioSystem.DEVICE_OUT_ALL_A2DP_SET) {
+                    if ((deviceType & device) == deviceType) {
+                        return deviceType;
+                    }
+                }
             }
         }
         return device;
@@ -4393,12 +4407,16 @@
         mDeviceBroker.postBluetoothA2dpDeviceConfigChange(device);
     }
 
-    private static final int DEVICE_MEDIA_UNMUTED_ON_PLUG =
-            AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
-            AudioSystem.DEVICE_OUT_LINE |
-            AudioSystem.DEVICE_OUT_ALL_A2DP |
-            AudioSystem.DEVICE_OUT_ALL_USB |
-            AudioSystem.DEVICE_OUT_HDMI;
+    private static final Set<Integer> DEVICE_MEDIA_UNMUTED_ON_PLUG_SET;
+    static {
+        DEVICE_MEDIA_UNMUTED_ON_PLUG_SET = new HashSet<>();
+        DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_WIRED_HEADSET);
+        DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE);
+        DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_LINE);
+        DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.addAll(AudioSystem.DEVICE_OUT_ALL_A2DP_SET);
+        DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.addAll(AudioSystem.DEVICE_OUT_ALL_USB_SET);
+        DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_HDMI);
+    }
 
     /** only public for mocking/spying, do not call outside of AudioService */
     @VisibleForTesting
@@ -4414,7 +4432,7 @@
         }
 
         if (mNm.getZenMode() != Settings.Global.ZEN_MODE_NO_INTERRUPTIONS
-                && (newDevice & DEVICE_MEDIA_UNMUTED_ON_PLUG) != 0
+                && DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.contains(newDevice)
                 && mStreamStates[AudioSystem.STREAM_MUSIC].mIsMuted
                 && mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(newDevice) != 0
                 && (newDevice & AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC)) != 0) {
@@ -4543,14 +4561,7 @@
                 }
             }
             synchronized (VolumeStreamState.class) {
-                int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
-
-                for (int i = 0; remainingDevices != 0; i++) {
-                    int device = (1 << i);
-                    if ((device & remainingDevices) == 0) {
-                        continue;
-                    }
-                    remainingDevices &= ~device;
+                for (int device : AudioSystem.DEVICE_OUT_ALL_SET) {
 
                     // retrieve current volume for device
                     // if no volume stored for current stream and device, use default volume if default
@@ -4610,11 +4621,12 @@
             int index;
             if (mIsMuted) {
                 index = 0;
-            } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && isAvrcpAbsVolSupported) {
+            } else if (AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
+                    && isAvrcpAbsVolSupported) {
                 index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
-            } else if ((device & mFullVolumeDevices) != 0) {
+            } else if (mFullVolumeDevices.contains(device)) {
                 index = (mIndexMax + 5)/10;
-            } else if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0) {
+            } else if (device == AudioSystem.DEVICE_OUT_HEARING_AID) {
                 index = (mIndexMax + 5)/10;
             } else {
                 index = (getIndex(device) + 5)/10;
@@ -4632,12 +4644,12 @@
                     if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
                         if (mIsMuted) {
                             index = 0;
-                        } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
-                                isAvrcpAbsVolSupported) {
+                        } else if (AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
+                                && isAvrcpAbsVolSupported) {
                             index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
-                        } else if ((device & mFullVolumeDevices) != 0) {
+                        } else if (mFullVolumeDevices.contains(device)) {
                             index = (mIndexMax + 5)/10;
-                        } else if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0) {
+                        } else if (device == AudioSystem.DEVICE_OUT_HEARING_AID) {
                             index = (mIndexMax + 5)/10;
                         } else {
                             index = (mIndexMap.valueAt(i) + 5)/10;
@@ -4698,7 +4710,7 @@
                             && device == AudioSystem.DEVICE_OUT_SPEAKER) {
                         for (int i = 0; i < mIndexMap.size(); i++) {
                             int otherDevice = mIndexMap.keyAt(i);
-                            if ((otherDevice & AudioSystem.DEVICE_OUT_ALL_SCO) != 0) {
+                            if (AudioSystem.DEVICE_OUT_ALL_SCO_SET.contains(otherDevice)) {
                                 mIndexMap.put(otherDevice, index);
                             }
                         }
@@ -4836,8 +4848,8 @@
                     for (int i = 0; i < mIndexMap.size(); i++) {
                         int device = mIndexMap.keyAt(i);
                         int index = mIndexMap.valueAt(i);
-                        if (((device & mFullVolumeDevices) != 0)
-                                || (((device & mFixedVolumeDevices) != 0) && index != 0)) {
+                        if (mFullVolumeDevices.contains(device)
+                                || (mFixedVolumeDevices.contains(device) && index != 0)) {
                             mIndexMap.put(device, mIndexMax);
                         }
                         applyDeviceVolume_syncVSS(device, isAvrcpAbsVolSupported);
@@ -5008,7 +5020,7 @@
                     // that may have a different device selected
                     int streamDevice = getDeviceForStream(streamType);
                     if ((device != streamDevice) && isAvrcpAbsVolSupported
-                            && ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
+                            && AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)) {
                         mStreamStates[streamType].applyDeviceVolume_syncVSS(device,
                                 isAvrcpAbsVolSupported);
                     }
@@ -5337,7 +5349,7 @@
     }
 
     /*package*/ void checkMusicActive(int deviceType, String caller) {
-        if ((deviceType & mSafeMediaVolumeDevices) != 0) {
+        if (mSafeMediaVolumeDevices.contains(deviceType)) {
             sendMsg(mAudioHandler,
                     MSG_CHECK_MUSIC_ACTIVE,
                     SENDMSG_REPLACE,
@@ -5783,9 +5795,9 @@
     // the headset is compliant to EN 60950 with a max loudness of 100dB SPL.
     private int mSafeUsbMediaVolumeIndex;
     // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
-    /*package*/ final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET
-            | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE
-            | AudioSystem.DEVICE_OUT_USB_HEADSET;
+    /*package*/ final Set<Integer> mSafeMediaVolumeDevices = new HashSet<>(
+            Arrays.asList(AudioSystem.DEVICE_OUT_WIRED_HEADSET,
+                    AudioSystem.DEVICE_OUT_WIRED_HEADPHONE, AudioSystem.DEVICE_OUT_USB_HEADSET));
     // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
     // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
     // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
@@ -5795,7 +5807,7 @@
     private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000;  // 30s after boot completed
 
     private int safeMediaVolumeIndex(int device) {
-        if ((device & mSafeMediaVolumeDevices) == 0) {
+        if (!mSafeMediaVolumeDevices.contains(device)) {
             return MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC];
         }
         if (device == AudioSystem.DEVICE_OUT_USB_HEADSET) {
@@ -5830,14 +5842,9 @@
 
     private void enforceSafeMediaVolume(String caller) {
         VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
-        int devices = mSafeMediaVolumeDevices;
-        int i = 0;
+        Set<Integer> devices = mSafeMediaVolumeDevices;
 
-        while (devices != 0) {
-            int device = 1 << i++;
-            if ((device & devices) == 0) {
-                continue;
-            }
+        for (int device : devices) {
             int index = streamState.getIndex(device);
             if (index > safeMediaVolumeIndex(device)) {
                 streamState.setIndex(safeMediaVolumeIndex(device), device, caller);
@@ -5849,16 +5856,15 @@
                         streamState,
                         0);
             }
-            devices &= ~device;
         }
     }
 
     private boolean checkSafeMediaVolume(int streamType, int index, int device) {
         synchronized (mSafeMediaVolumeStateLock) {
-            if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
-                    (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
-                    ((device & mSafeMediaVolumeDevices) != 0) &&
-                    (index > safeMediaVolumeIndex(device))) {
+            if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)
+                    && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC)
+                    && (mSafeMediaVolumeDevices.contains(device))
+                    && (index > safeMediaVolumeIndex(device))) {
                 return false;
             }
             return true;
@@ -5899,14 +5905,14 @@
             if (DEBUG_VOL) {
                 Log.d(TAG, "CEC sink: setting HDMI as full vol device");
             }
-            mFullVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
+            mFullVolumeDevices.add(AudioSystem.DEVICE_OUT_HDMI);
         } else {
             if (DEBUG_VOL) {
                 Log.d(TAG, "TV, no CEC: setting HDMI as regular vol device");
             }
             // Android TV devices without CEC service apply software volume on
             // HDMI output
-            mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
+            mFullVolumeDevices.remove(AudioSystem.DEVICE_OUT_HDMI);
         }
 
         checkAddAllFixedVolumeDevices(AudioSystem.DEVICE_OUT_HDMI,
@@ -6127,6 +6133,19 @@
         pw.println();
     }
 
+    private String dumpDeviceTypes(@NonNull Set<Integer> deviceTypes) {
+        Iterator<Integer> it = deviceTypes.iterator();
+        if (!it.hasNext()) {
+            return "";
+        }
+        final StringBuilder sb = new StringBuilder();
+        sb.append("0x" + Integer.toHexString(it.next()));
+        while (it.hasNext()) {
+            sb.append("," + "0x" + Integer.toHexString(it.next()));
+        }
+        return sb.toString();
+    }
+
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
@@ -6163,7 +6182,7 @@
         pw.println(mDeviceBroker.isAvrcpAbsoluteVolumeSupported());
         pw.print("  mIsSingleVolume="); pw.println(mIsSingleVolume);
         pw.print("  mUseFixedVolume="); pw.println(mUseFixedVolume);
-        pw.print("  mFixedVolumeDevices=0x"); pw.println(Integer.toHexString(mFixedVolumeDevices));
+        pw.print("  mFixedVolumeDevices="); pw.println(dumpDeviceTypes(mFixedVolumeDevices));
         pw.print("  mHdmiCecSink="); pw.println(mHdmiCecSink);
         pw.print("  mHdmiAudioSystemClient="); pw.println(mHdmiAudioSystemClient);
         pw.print("  mHdmiPlaybackClient="); pw.println(mHdmiPlaybackClient);