Merge "LeAudio: Fix audio modes priority" into tm-qpr-dev
diff --git a/android/app/src/com/android/bluetooth/a2dp/A2dpService.java b/android/app/src/com/android/bluetooth/a2dp/A2dpService.java
index 03662a0..cffc4ed6 100644
--- a/android/app/src/com/android/bluetooth/a2dp/A2dpService.java
+++ b/android/app/src/com/android/bluetooth/a2dp/A2dpService.java
@@ -494,13 +494,32 @@
                 previousActiveDevice = mActiveDevice;
             }
 
+            int prevActiveConnectionState = getConnectionState(previousActiveDevice);
+
+            // As per b/202602952, if we remove the active device due to a disconnection,
+            // we need to check if another device is connected and set it active instead.
+            // Calling this before any other active related calls has the same effect as
+            // a classic active device switch.
+            BluetoothDevice fallbackdevice = getFallbackDevice();
+            if (fallbackdevice != null && prevActiveConnectionState
+                    != BluetoothProfile.STATE_CONNECTED) {
+                setActiveDevice(fallbackdevice);
+                return;
+            }
+
             // This needs to happen before we inform the audio manager that the device
             // disconnected. Please see comment in updateAndBroadcastActiveDevice() for why.
             updateAndBroadcastActiveDevice(null);
 
-            // Make sure the Audio Manager knows the previous Active device is removed.
+            // Make sure the Audio Manager knows the previous Active device is disconnected.
+            // However, if A2DP is still connected and not forcing stop audio for that remote
+            // device, the user has explicitly switched the output to the local device and music
+            // should continue playing. Otherwise, the remote device has been indeed disconnected
+            // and audio should be suspended before switching the output to the local device.
+            boolean stopAudio = forceStopPlayingAudio || (prevActiveConnectionState
+                        != BluetoothProfile.STATE_CONNECTED);
             mAudioManager.handleBluetoothActiveDeviceChanged(null, previousActiveDevice,
-                    BluetoothProfileConnectionInfo.createA2dpInfo(!forceStopPlayingAudio, -1));
+                    BluetoothProfileConnectionInfo.createA2dpInfo(!stopAudio, -1));
 
             synchronized (mStateMachines) {
                 // Make sure the Active device in native layer is set to null and audio is off
@@ -544,22 +563,10 @@
      * @return true on success, otherwise false
      */
     public boolean setActiveDevice(BluetoothDevice device) {
-        return setActiveDevice(device, false);
-    }
-
-    /**
-     * Set the active device.
-     *
-     * @param device the active device
-     * @param hasFallbackDevice whether it has fallback device when the {@code device}
-     *                          is {@code null}.
-     * @return true on success, otherwise false
-     */
-    public boolean setActiveDevice(BluetoothDevice device, boolean hasFallbackDevice) {
         synchronized (mActiveSwitchingGuard) {
             if (device == null) {
                 // Remove active device and continue playing audio only if necessary.
-                removeActiveDevice(!hasFallbackDevice);
+                removeActiveDevice(false);
                 return true;
             }
 
@@ -1246,9 +1253,10 @@
         if (toState == BluetoothProfile.STATE_CONNECTED && (mMaxConnectedAudioDevices == 1)) {
             setActiveDevice(device);
         }
-
-        // When disconnected, ActiveDeviceManager will call setActiveDevice(null)
-
+        // Check if the active device is not connected anymore
+        if (isActiveDevice(device) && (fromState == BluetoothProfile.STATE_CONNECTED)) {
+            setActiveDevice(null);
+        }
         // Check if the device is disconnected - if unbond, remove the state machine
         if (toState == BluetoothProfile.STATE_DISCONNECTED) {
             if (mAdapterService.getBondState(device) == BluetoothDevice.BOND_NONE) {
diff --git a/android/app/src/com/android/bluetooth/btservice/ActiveDeviceManager.java b/android/app/src/com/android/bluetooth/btservice/ActiveDeviceManager.java
index 1d2666e..f043394 100644
--- a/android/app/src/com/android/bluetooth/btservice/ActiveDeviceManager.java
+++ b/android/app/src/com/android/bluetooth/btservice/ActiveDeviceManager.java
@@ -49,7 +49,6 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
-import java.util.concurrent.RejectedExecutionException;
 
 /**
  * The active device manager is responsible for keeping track of the
@@ -125,32 +124,24 @@
     private static final int MESSAGE_HAP_ACTION_CONNECTION_STATE_CHANGED = 10;
     private static final int MESSAGE_HAP_ACTION_ACTIVE_DEVICE_CHANGED = 11;
 
-    // Used when it is needed to find a fallback device
-    private static final int PROFILE_NOT_DECIDED_YET = -1;
-    // Used for built-in audio device
-    private static final int PROFILE_USE_BUILTIN_AUDIO_DEVICE = 0;
-
     private final AdapterService mAdapterService;
     private final ServiceFactory mFactory;
     private HandlerThread mHandlerThread = null;
     private Handler mHandler = null;
     private final AudioManager mAudioManager;
     private final AudioManagerAudioDeviceCallback mAudioManagerAudioDeviceCallback;
-    private final AudioManagerOnModeChangedListener mAudioManagerOnModeChangedListener;
 
     private final List<BluetoothDevice> mA2dpConnectedDevices = new ArrayList<>();
     private final List<BluetoothDevice> mHfpConnectedDevices = new ArrayList<>();
     private final List<BluetoothDevice> mHearingAidConnectedDevices = new ArrayList<>();
     private final List<BluetoothDevice> mLeAudioConnectedDevices = new ArrayList<>();
     private final List<BluetoothDevice> mLeHearingAidConnectedDevices = new ArrayList<>();
-    private final List<BluetoothDevice> mPendingLeHearingAidActiveDevice = new ArrayList<>();
+    private List<BluetoothDevice> mPendingLeHearingAidActiveDevice = new ArrayList<>();
     private BluetoothDevice mA2dpActiveDevice = null;
     private BluetoothDevice mHfpActiveDevice = null;
     private BluetoothDevice mHearingAidActiveDevice = null;
     private BluetoothDevice mLeAudioActiveDevice = null;
     private BluetoothDevice mLeHearingAidActiveDevice = null;
-    private int mActiveMediaProfile = PROFILE_USE_BUILTIN_AUDIO_DEVICE;
-    private int mActiveCallProfile = PROFILE_USE_BUILTIN_AUDIO_DEVICE;
 
     // Broadcast receiver for all changes
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@@ -220,7 +211,6 @@
 
         @Override
         public void handleMessage(Message msg) {
-            boolean isMediaMode = isMediaMode(mAudioManager.getMode());
             switch (msg.what) {
                 case MESSAGE_ADAPTER_ACTION_STATE_CHANGED: {
                     Intent intent = (Intent) msg.obj;
@@ -255,24 +245,16 @@
                         if (mA2dpConnectedDevices.contains(device)) {
                             break;      // The device is already connected
                         }
-                        // New connected A2DP device
                         mA2dpConnectedDevices.add(device);
-                        if (mActiveMediaProfile != BluetoothProfile.HEARING_AID
-                                && mActiveMediaProfile != BluetoothProfile.HAP_CLIENT) {
-                            if (isMediaMode || mActiveCallProfile == BluetoothProfile.HEADSET) {
-                                // select the device as active if not lazy active
-                                setA2dpActiveDevice(device);
-                                setLeAudioActiveDevice(null, true);
-                                mActiveMediaProfile = BluetoothProfile.A2DP;
-                            } else {
-                                // Lazy active A2DP if it is not being used.
-                                mActiveMediaProfile = PROFILE_NOT_DECIDED_YET;
-                            }
+                        if (mHearingAidActiveDevice == null && mLeHearingAidActiveDevice == null) {
+                            // New connected device: select it as active
+                            setA2dpActiveDevice(device);
+                            setLeAudioActiveDevice(null);
                         }
                         break;
                     }
                     if (prevState == BluetoothProfile.STATE_CONNECTED) {
-                        // A2DP device disconnected
+                        // Device disconnected
                         if (DBG) {
                             Log.d(TAG,
                                     "handleMessage(MESSAGE_A2DP_ACTION_CONNECTION_STATE_CHANGED): "
@@ -280,15 +262,10 @@
                         }
                         mA2dpConnectedDevices.remove(device);
                         if (Objects.equals(mA2dpActiveDevice, device)) {
-                            mActiveMediaProfile = PROFILE_NOT_DECIDED_YET;
-                            if (isMediaMode) {
-                                if (!setFallbackDeviceActive()) {
-                                    mActiveMediaProfile = PROFILE_USE_BUILTIN_AUDIO_DEVICE;
-                                    setA2dpActiveDevice(null);
-                                }
-                            } else {
+                            if (mA2dpConnectedDevices.isEmpty()) {
                                 setA2dpActiveDevice(null);
                             }
+                            setFallbackDeviceActive();
                         }
                     }
                 }
@@ -302,12 +279,12 @@
                         Log.d(TAG, "handleMessage(MESSAGE_A2DP_ACTION_ACTIVE_DEVICE_CHANGED): "
                                 + "device= " + device);
                     }
-                    if (device != null) {
-                        mActiveMediaProfile = BluetoothProfile.A2DP;
-                        if (!Objects.equals(mA2dpActiveDevice, device)) {
-                            setHearingAidActiveDevice(null, true);
-                            setLeAudioActiveDevice(null, true);
-                        }
+                    if (device != null && !Objects.equals(mA2dpActiveDevice, device)) {
+                        setHearingAidActiveDevice(null);
+                        setLeAudioActiveDevice(null);
+                    }
+                    if (mHfpConnectedDevices.contains(device)) {
+                        setHfpActiveDevice(device);
                     }
                     // Just assign locally the new value
                     mA2dpActiveDevice = device;
@@ -334,24 +311,16 @@
                         if (mHfpConnectedDevices.contains(device)) {
                             break;      // The device is already connected
                         }
-                        // New connected HFP device.
                         mHfpConnectedDevices.add(device);
-                        if (mActiveCallProfile != BluetoothProfile.HEARING_AID
-                                && mActiveCallProfile != BluetoothProfile.HAP_CLIENT) {
-                            if (!isMediaMode || mActiveMediaProfile == BluetoothProfile.A2DP) {
-                                // select the device as active if not lazy active
-                                setHfpActiveDevice(device);
-                                setLeAudioActiveDevice(null);
-                                mActiveCallProfile = BluetoothProfile.HEADSET;
-                            } else {
-                                // Lazy active HFP if it is not being used.
-                                mActiveCallProfile = PROFILE_NOT_DECIDED_YET;
-                            }
+                        if (mHearingAidActiveDevice == null && mLeHearingAidActiveDevice == null) {
+                            // New connected device: select it as active
+                            setHfpActiveDevice(device);
+                            setLeAudioActiveDevice(null);
                         }
                         break;
                     }
                     if (prevState == BluetoothProfile.STATE_CONNECTED) {
-                        // HFP device disconnected
+                        // Device disconnected
                         if (DBG) {
                             Log.d(TAG,
                                     "handleMessage(MESSAGE_HFP_ACTION_CONNECTION_STATE_CHANGED): "
@@ -359,15 +328,10 @@
                         }
                         mHfpConnectedDevices.remove(device);
                         if (Objects.equals(mHfpActiveDevice, device)) {
-                            mActiveCallProfile = PROFILE_NOT_DECIDED_YET;
-                            if (!isMediaMode) {
-                                if (!setFallbackDeviceActive()) {
-                                    mActiveCallProfile = PROFILE_USE_BUILTIN_AUDIO_DEVICE;
-                                    setHfpActiveDevice(null);
-                                }
-                            } else {
+                            if (mHfpConnectedDevices.isEmpty()) {
                                 setHfpActiveDevice(null);
                             }
+                            setFallbackDeviceActive();
                         }
                     }
                 }
@@ -381,12 +345,12 @@
                         Log.d(TAG, "handleMessage(MESSAGE_HFP_ACTION_ACTIVE_DEVICE_CHANGED): "
                                 + "device= " + device);
                     }
-                    if (device != null) {
-                        mActiveCallProfile = BluetoothProfile.HEADSET;
-                        if (!Objects.equals(mHfpActiveDevice, device)) {
-                            setHearingAidActiveDevice(null, true);
-                            setLeAudioActiveDevice(null, true);
-                        }
+                    if (device != null && !Objects.equals(mHfpActiveDevice, device)) {
+                        setHearingAidActiveDevice(null);
+                        setLeAudioActiveDevice(null);
+                    }
+                    if (mA2dpConnectedDevices.contains(device)) {
+                        setA2dpActiveDevice(device);
                     }
                     // Just assign locally the new value
                     mHfpActiveDevice = device;
@@ -413,38 +377,25 @@
                             break;      // The device is already connected
                         }
                         mHearingAidConnectedDevices.add(device);
-                        // New connected hearing aid device: select it as active
-                        mActiveMediaProfile = BluetoothProfile.HEARING_AID;
-                        mActiveCallProfile = BluetoothProfile.HEARING_AID;
+                        // New connected device: select it as active
                         setHearingAidActiveDevice(device);
-                        setA2dpActiveDevice(null, true);
+                        setA2dpActiveDevice(null);
                         setHfpActiveDevice(null);
-                        setLeAudioActiveDevice(null, true);
+                        setLeAudioActiveDevice(null);
                         break;
                     }
                     if (prevState == BluetoothProfile.STATE_CONNECTED) {
-                        // Hearing aid device disconnected
+                        // Device disconnected
                         if (DBG) {
                             Log.d(TAG, "handleMessage(MESSAGE_HEARING_AID_ACTION_CONNECTION_STATE"
                                     + "_CHANGED): device " + device + " disconnected");
                         }
                         mHearingAidConnectedDevices.remove(device);
                         if (Objects.equals(mHearingAidActiveDevice, device)) {
-                            if (mActiveMediaProfile == BluetoothProfile.HEARING_AID) {
-                                mActiveMediaProfile = PROFILE_NOT_DECIDED_YET;
-                            }
-                            if (mActiveCallProfile == BluetoothProfile.HEARING_AID) {
-                                mActiveCallProfile = PROFILE_NOT_DECIDED_YET;
-                            }
-                            if (!setFallbackDeviceActive()) {
+                            if (mHearingAidConnectedDevices.isEmpty()) {
                                 setHearingAidActiveDevice(null);
-                                if (mActiveMediaProfile == PROFILE_NOT_DECIDED_YET) {
-                                    mActiveMediaProfile = PROFILE_USE_BUILTIN_AUDIO_DEVICE;
-                                }
-                                if (mActiveCallProfile == PROFILE_NOT_DECIDED_YET) {
-                                    mActiveCallProfile = PROFILE_USE_BUILTIN_AUDIO_DEVICE;
-                                }
                             }
+                            setFallbackDeviceActive();
                         }
                     }
                 }
@@ -458,18 +409,13 @@
                         Log.d(TAG, "handleMessage(MESSAGE_HA_ACTION_ACTIVE_DEVICE_CHANGED): "
                                 + "device= " + device);
                     }
-                    if (device != null && !Objects.equals(mHearingAidActiveDevice, device)) {
-                        setA2dpActiveDevice(null, true);
-                        setHfpActiveDevice(null);
-                        setLeAudioActiveDevice(null, true);
-                        if (isMediaMode) {
-                            mActiveMediaProfile = BluetoothProfile.HEARING_AID;
-                        } else {
-                            mActiveCallProfile = BluetoothProfile.HEARING_AID;
-                        }
-                    }
                     // Just assign locally the new value
                     mHearingAidActiveDevice = device;
+                    if (device != null) {
+                        setA2dpActiveDevice(null);
+                        setHfpActiveDevice(null);
+                        setLeAudioActiveDevice(null);
+                    }
                 }
                 break;
 
@@ -483,80 +429,43 @@
                         // Nothing has changed
                         break;
                     }
-                    final LeAudioService leAudioService = mFactory.getLeAudioService();
-
                     if (nextState == BluetoothProfile.STATE_CONNECTED) {
                         // Device connected
                         if (DBG) {
                             Log.d(TAG, "handleMessage(MESSAGE_LE_AUDIO_ACTION_CONNECTION_STATE"
                                     + "_CHANGED): device " + device + " connected");
                         }
-                        if (leAudioService != null && device != null) {
-                            leAudioService.deviceConnected(device);
-                        }
                         if (mLeAudioConnectedDevices.contains(device)) {
                             break;      // The device is already connected
                         }
                         mLeAudioConnectedDevices.add(device);
-                        if (mPendingLeHearingAidActiveDevice.contains(device)) {
-                            // LE hearing aid connected
-                            mActiveMediaProfile = BluetoothProfile.HAP_CLIENT;
-                            mActiveCallProfile = BluetoothProfile.HAP_CLIENT;
-                            setLeHearingAidActiveDevice(device);
-                            setHearingAidActiveDevice(null, true);
-                            setA2dpActiveDevice(null, true);
+                        if (mHearingAidActiveDevice == null && mLeHearingAidActiveDevice == null
+                                && mPendingLeHearingAidActiveDevice.isEmpty()) {
+                            // New connected device: select it as active
+                            setLeAudioActiveDevice(device);
+                            setA2dpActiveDevice(null);
                             setHfpActiveDevice(null);
-                        } else {
-                            boolean setLeAudioActive = false;
-                            if (mActiveMediaProfile != BluetoothProfile.HEARING_AID
-                                    && mActiveMediaProfile != BluetoothProfile.HAP_CLIENT) {
-                                mActiveMediaProfile = BluetoothProfile.LE_AUDIO;
-                                setLeAudioActive |= isMediaMode;
-                            }
-                            if (mActiveCallProfile != BluetoothProfile.HEARING_AID
-                                    && mActiveCallProfile != BluetoothProfile.HAP_CLIENT) {
-                                mActiveCallProfile = BluetoothProfile.LE_AUDIO;
-                                setLeAudioActive |= !isMediaMode;
-                            }
-                            if (setLeAudioActive) {
-                                setLeAudioActiveDevice(device);
-                                setA2dpActiveDevice(null, true);
-                                setHfpActiveDevice(null);
-                                setHearingAidActiveDevice(null, true);
-                            }
+                        } else if (mPendingLeHearingAidActiveDevice.contains(device)) {
+                            setLeHearingAidActiveDevice(device);
+                            setHearingAidActiveDevice(null);
+                            setA2dpActiveDevice(null);
+                            setHfpActiveDevice(null);
                         }
                         break;
                     }
                     if (prevState == BluetoothProfile.STATE_CONNECTED) {
-                        // LE audio device disconnected
+                        // Device disconnected
                         if (DBG) {
                             Log.d(TAG, "handleMessage(MESSAGE_LE_AUDIO_ACTION_CONNECTION_STATE"
                                     + "_CHANGED): device " + device + " disconnected");
                         }
                         mLeAudioConnectedDevices.remove(device);
                         mLeHearingAidConnectedDevices.remove(device);
-                        boolean hasFallbackDevice = false;
                         if (Objects.equals(mLeAudioActiveDevice, device)) {
-                            if (mActiveMediaProfile == BluetoothProfile.LE_AUDIO
-                                    || mActiveMediaProfile == BluetoothProfile.HAP_CLIENT) {
-                                mActiveMediaProfile = PROFILE_NOT_DECIDED_YET;
-                            }
-                            if (mActiveCallProfile == BluetoothProfile.LE_AUDIO
-                                    || mActiveCallProfile == BluetoothProfile.HAP_CLIENT) {
-                                mActiveCallProfile = PROFILE_NOT_DECIDED_YET;
-                            }
-                            if (!setFallbackDeviceActive()) {
+                            if (mLeAudioConnectedDevices.isEmpty()) {
                                 setLeAudioActiveDevice(null);
-                                if (mActiveMediaProfile == PROFILE_NOT_DECIDED_YET) {
-                                    mActiveMediaProfile = PROFILE_USE_BUILTIN_AUDIO_DEVICE;
-                                }
-                                if (mActiveCallProfile == PROFILE_NOT_DECIDED_YET) {
-                                    mActiveCallProfile = PROFILE_USE_BUILTIN_AUDIO_DEVICE;
-                                }
                             }
-                        }
-                        if (leAudioService != null && device != null) {
-                            leAudioService.deviceDisconnected(device, hasFallbackDevice);
+                            setFallbackDeviceActive();
                         }
                     }
                 }
@@ -573,20 +482,12 @@
                         Log.d(TAG, "handleMessage(MESSAGE_LE_AUDIO_ACTION_ACTIVE_DEVICE_CHANGED): "
                                 + "device= " + device);
                     }
-
-                    if (device != null && !Objects.equals(mLeAudioActiveDevice, device)) {
-                        setA2dpActiveDevice(null, true);
-                        setHfpActiveDevice(null);
-                        setHearingAidActiveDevice(null, true);
-                        int profile = mLeHearingAidConnectedDevices.contains(device)
-                                ? BluetoothProfile.HAP_CLIENT : BluetoothProfile.LE_AUDIO;
-                        if (isMediaMode) {
-                            mActiveMediaProfile = profile;
-                        } else {
-                            mActiveCallProfile = profile;
-                        }
-                    }
                     // Just assign locally the new value
+                    if (device != null && !Objects.equals(mLeAudioActiveDevice, device)) {
+                        setA2dpActiveDevice(null);
+                        setHfpActiveDevice(null);
+                        setHearingAidActiveDevice(null);
+                    }
                     mLeAudioActiveDevice = device;
                 }
                 break;
@@ -613,22 +514,19 @@
                         mLeHearingAidConnectedDevices.add(device);
                         if (!mLeAudioConnectedDevices.contains(device)) {
                             mPendingLeHearingAidActiveDevice.add(device);
+                        } else if (Objects.equals(mLeAudioActiveDevice, device)) {
+                            mLeHearingAidActiveDevice = device;
                         } else {
-                            mActiveMediaProfile = BluetoothProfile.HAP_CLIENT;
-                            mActiveCallProfile = BluetoothProfile.HAP_CLIENT;
-                            if (Objects.equals(mLeAudioActiveDevice, device)) {
-                                mLeHearingAidActiveDevice = device;
-                            } else {
-                                setLeHearingAidActiveDevice(device);
-                                setHearingAidActiveDevice(null, true);
-                                setA2dpActiveDevice(null, true);
-                                setHfpActiveDevice(null);
-                            }
+                            // New connected device: select it as active
+                            setLeHearingAidActiveDevice(device);
+                            setHearingAidActiveDevice(null);
+                            setA2dpActiveDevice(null);
+                            setHfpActiveDevice(null);
                         }
                         break;
                     }
                     if (prevState == BluetoothProfile.STATE_CONNECTED) {
-                        // LE hearing aid device disconnected
+                        // Device disconnected
                         if (DBG) {
                             Log.d(TAG, "handleMessage(MESSAGE_HAP_ACTION_CONNECTION_STATE"
                                     + "_CHANGED): device " + device + " disconnected");
@@ -655,14 +553,9 @@
                     }
                     // Just assign locally the new value
                     if (device != null && !Objects.equals(mLeHearingAidActiveDevice, device)) {
-                        if (isMediaMode) {
-                            mActiveMediaProfile = BluetoothProfile.HAP_CLIENT;
-                        } else {
-                            mActiveCallProfile = BluetoothProfile.HAP_CLIENT;
-                        }
-                        setHearingAidActiveDevice(null, true);
-                        setA2dpActiveDevice(null, true);
+                        setA2dpActiveDevice(null);
                         setHfpActiveDevice(null);
+                        setHearingAidActiveDevice(null);
                     }
                     mLeHearingAidActiveDevice = mLeAudioActiveDevice = device;
                 }
@@ -671,167 +564,6 @@
         }
     }
 
-    private class AudioManagerOnModeChangedListener implements AudioManager.OnModeChangedListener {
-        public void onModeChanged(int mode) {
-            if (isMediaMode(mode)) {
-                setMediaProfileActive();
-            } else {
-                setCallProfileActive();
-            }
-        }
-
-        private void setMediaProfileActive() {
-            BluetoothDevice device = null;
-            switch (mActiveMediaProfile) {
-                case PROFILE_NOT_DECIDED_YET: {
-                    if (!setFallbackDeviceActive()) {
-                        mActiveMediaProfile = PROFILE_USE_BUILTIN_AUDIO_DEVICE;
-                    }
-                    break;
-                }
-
-                case BluetoothProfile.A2DP: {
-                    if (mA2dpActiveDevice == null) {
-                        A2dpService a2dpService = mFactory.getA2dpService();
-                        if (a2dpService != null) {
-                            device = a2dpService.getFallbackDevice();
-                        }
-                        if (device != null) {
-                            setA2dpActiveDevice(device);
-                            setHearingAidActiveDevice(null, true);
-                            setLeAudioActiveDevice(null, true);
-                        } else {
-                            mActiveMediaProfile = PROFILE_USE_BUILTIN_AUDIO_DEVICE;
-                        }
-                    }
-                    break;
-                }
-
-                case BluetoothProfile.HEARING_AID: {
-                    if (mHearingAidActiveDevice == null) {
-                        DatabaseManager dbManager = mAdapterService.getDatabase();
-                        if (dbManager != null) {
-                            device = dbManager.getMostRecentlyConnectedDevicesInList(
-                                    mHearingAidConnectedDevices);
-                        }
-                        if (device != null) {
-                            setHearingAidActiveDevice(device);
-                            setA2dpActiveDevice(null, true);
-                            setLeAudioActiveDevice(null, true);
-                        } else {
-                            mActiveMediaProfile = PROFILE_USE_BUILTIN_AUDIO_DEVICE;
-                        }
-                    }
-                    break;
-                }
-
-                case BluetoothProfile.LE_AUDIO: {
-                    if (mLeAudioActiveDevice == null) {
-                        DatabaseManager dbManager = mAdapterService.getDatabase();
-                        if (dbManager != null) {
-                            device = dbManager.getMostRecentlyConnectedDevicesInList(
-                                    mLeAudioConnectedDevices);
-                        }
-                        if (device != null) {
-                            setLeAudioActiveDevice(device);
-                            setA2dpActiveDevice(null, true);
-                            setHfpActiveDevice(null);
-                            setHearingAidActiveDevice(null, true);
-                        } else {
-                            mActiveMediaProfile = PROFILE_USE_BUILTIN_AUDIO_DEVICE;
-                        }
-                    }
-                    break;
-                }
-
-                case BluetoothProfile.HAP_CLIENT: {
-                    if (mLeHearingAidActiveDevice == null) {
-                        DatabaseManager dbManager = mAdapterService.getDatabase();
-                        if (dbManager != null) {
-                            device = dbManager.getMostRecentlyConnectedDevicesInList(
-                                    mLeHearingAidConnectedDevices);
-                        }
-                        if (device != null) {
-                            setLeHearingAidActiveDevice(device);
-                            setA2dpActiveDevice(null, true);
-                            setHfpActiveDevice(null);
-                            setHearingAidActiveDevice(null, true);
-                        } else {
-                            mActiveMediaProfile = PROFILE_USE_BUILTIN_AUDIO_DEVICE;
-                        }
-                    }
-                    break;
-                }
-            }
-        }
-
-        private void setCallProfileActive() {
-            BluetoothDevice device = null;
-            switch (mActiveCallProfile) {
-                case PROFILE_NOT_DECIDED_YET: {
-                    if (!setFallbackDeviceActive()) {
-                        mActiveCallProfile = PROFILE_USE_BUILTIN_AUDIO_DEVICE;
-                    }
-                    break;
-                }
-
-                case BluetoothProfile.HEADSET: {
-                    if (mHfpActiveDevice == null) {
-                        HeadsetService headsetService = mFactory.getHeadsetService();
-                        if (headsetService != null) {
-                            device = headsetService.getFallbackDevice();
-                        }
-                        if (device != null) {
-                            setHfpActiveDevice(device);
-                            setHearingAidActiveDevice(null, true);
-                            setLeAudioActiveDevice(null, true);
-                        } else {
-                            mActiveCallProfile = PROFILE_USE_BUILTIN_AUDIO_DEVICE;
-                        }
-                    }
-                    break;
-                }
-
-                case BluetoothProfile.HEARING_AID: {
-                    if (mHearingAidActiveDevice == null) {
-                        DatabaseManager dbManager = mAdapterService.getDatabase();
-                        if (dbManager != null) {
-                            device = dbManager.getMostRecentlyConnectedDevicesInList(
-                                    mHearingAidConnectedDevices);
-                        }
-                        if (device != null) {
-                            setHearingAidActiveDevice(device);
-                            setHfpActiveDevice(null);
-                            setLeAudioActiveDevice(null);
-                        } else {
-                            mActiveCallProfile = PROFILE_USE_BUILTIN_AUDIO_DEVICE;
-                        }
-                    }
-                    break;
-                }
-
-                case BluetoothProfile.LE_AUDIO: {
-                    if (mLeAudioActiveDevice == null) {
-                        DatabaseManager dbManager = mAdapterService.getDatabase();
-                        if (dbManager != null) {
-                            device = dbManager.getMostRecentlyConnectedDevicesInList(
-                                    mLeAudioConnectedDevices);
-                        }
-                        if (device != null) {
-                            setLeAudioActiveDevice(device);
-                            setA2dpActiveDevice(null, true);
-                            setHfpActiveDevice(null);
-                            setHearingAidActiveDevice(null, true);
-                        } else {
-                            mActiveCallProfile = PROFILE_USE_BUILTIN_AUDIO_DEVICE;
-                        }
-                    }
-                    break;
-                }
-            }
-        }
-    }
-
     /** Notifications of audio device connection and disconnection events. */
     @SuppressLint("AndroidFrameworkRequiresPermission")
     private class AudioManagerAudioDeviceCallback extends AudioDeviceCallback {
@@ -878,7 +610,6 @@
         mFactory = factory;
         mAudioManager = service.getSystemService(AudioManager.class);
         mAudioManagerAudioDeviceCallback = new AudioManagerAudioDeviceCallback();
-        mAudioManagerOnModeChangedListener = new AudioManagerOnModeChangedListener();
     }
 
     void start() {
@@ -905,11 +636,6 @@
         mAdapterService.registerReceiver(mReceiver, filter);
 
         mAudioManager.registerAudioDeviceCallback(mAudioManagerAudioDeviceCallback, mHandler);
-        mAudioManager.addOnModeChangedListener(command -> {
-            if (!mHandler.post(command)) {
-                throw new RejectedExecutionException(mHandler + " is shutting down");
-            }
-        }, mAudioManagerOnModeChangedListener);
     }
 
     void cleanup() {
@@ -918,7 +644,6 @@
         }
 
         mAudioManager.unregisterAudioDeviceCallback(mAudioManagerAudioDeviceCallback);
-        mAudioManager.removeOnModeChangedListener(mAudioManagerOnModeChangedListener);
         mAdapterService.unregisterReceiver(mReceiver);
         if (mHandlerThread != null) {
             mHandlerThread.quit();
@@ -942,10 +667,6 @@
     }
 
     private void setA2dpActiveDevice(BluetoothDevice device) {
-        setA2dpActiveDevice(device, false);
-    }
-
-    private void setA2dpActiveDevice(BluetoothDevice device, boolean hasFallbackDevice) {
         if (DBG) {
             Log.d(TAG, "setA2dpActiveDevice(" + device + ")");
         }
@@ -953,7 +674,7 @@
         if (a2dpService == null) {
             return;
         }
-        if (!a2dpService.setActiveDevice(device, hasFallbackDevice)) {
+        if (!a2dpService.setActiveDevice(device)) {
             return;
         }
         mA2dpActiveDevice = device;
@@ -975,10 +696,6 @@
     }
 
     private void setHearingAidActiveDevice(BluetoothDevice device) {
-        setHearingAidActiveDevice(device, false);
-    }
-
-    private void setHearingAidActiveDevice(BluetoothDevice device, boolean hasFallbackDevice) {
         if (DBG) {
             Log.d(TAG, "setHearingAidActiveDevice(" + device + ")");
         }
@@ -986,16 +703,13 @@
         if (hearingAidService == null) {
             return;
         }
-        if (!hearingAidService.setActiveDevice(device, hasFallbackDevice)) {
+        if (!hearingAidService.setActiveDevice(device)) {
             return;
         }
         mHearingAidActiveDevice = device;
     }
-    private void setLeAudioActiveDevice(BluetoothDevice device) {
-        setLeAudioActiveDevice(device, false);
-    }
 
-    private void setLeAudioActiveDevice(BluetoothDevice device, boolean hasFallbackDevice) {
+    private void setLeAudioActiveDevice(BluetoothDevice device) {
         if (DBG) {
             Log.d(TAG, "setLeAudioActiveDevice(" + device + ")");
         }
@@ -1003,7 +717,7 @@
         if (leAudioService == null) {
             return;
         }
-        if (!leAudioService.setActiveDevice(device, hasFallbackDevice)) {
+        if (!leAudioService.setActiveDevice(device)) {
             return;
         }
         mLeAudioActiveDevice = device;
@@ -1014,9 +728,6 @@
     }
 
     private void setLeHearingAidActiveDevice(BluetoothDevice device) {
-        if (DBG) {
-            Log.d(TAG, "setLeHearingAidActiveDevice(" + device + ")");
-        }
         if (!Objects.equals(mLeAudioActiveDevice, device)) {
             setLeAudioActiveDevice(device);
         }
@@ -1027,32 +738,13 @@
         }
     }
 
-    private boolean isMediaMode(int mode) {
-        switch (mode) {
-            case AudioManager.MODE_RINGTONE:
-                final HeadsetService headsetService = mFactory.getHeadsetService();
-                if (headsetService != null && headsetService.isInbandRingingEnabled()) {
-                    return false;
-                }
-                return true;
-            case AudioManager.MODE_IN_CALL:
-            case AudioManager.MODE_IN_COMMUNICATION:
-            case AudioManager.MODE_CALL_SCREENING:
-            case AudioManager.MODE_CALL_REDIRECT:
-            case AudioManager.MODE_COMMUNICATION_REDIRECT:
-                return false;
-            default:
-                return true;
-        }
-    }
-
-    private boolean setFallbackDeviceActive() {
+    private void setFallbackDeviceActive() {
         if (DBG) {
             Log.d(TAG, "setFallbackDeviceActive");
         }
         DatabaseManager dbManager = mAdapterService.getDatabase();
         if (dbManager == null) {
-            return false;
+            return;
         }
         List<BluetoothDevice> connectedHearingAidDevices = new ArrayList<>();
         if (!mHearingAidConnectedDevices.isEmpty()) {
@@ -1070,31 +762,19 @@
                         Log.d(TAG, "set hearing aid device active: " + device);
                     }
                     setHearingAidActiveDevice(device);
-                    setA2dpActiveDevice(null, true);
+                    setA2dpActiveDevice(null);
                     setHfpActiveDevice(null);
-                    setLeAudioActiveDevice(null, true);
-                    if (mActiveMediaProfile == PROFILE_NOT_DECIDED_YET) {
-                        mActiveMediaProfile = BluetoothProfile.HEARING_AID;
-                    }
-                    if (mActiveCallProfile == PROFILE_NOT_DECIDED_YET) {
-                        mActiveCallProfile = BluetoothProfile.HEARING_AID;
-                    }
+                    setLeAudioActiveDevice(null);
                 } else {
                     if (DBG) {
                         Log.d(TAG, "set LE hearing aid device active: " + device);
                     }
                     setLeHearingAidActiveDevice(device);
-                    setHearingAidActiveDevice(null, true);
-                    setA2dpActiveDevice(null, true);
+                    setHearingAidActiveDevice(null);
+                    setA2dpActiveDevice(null);
                     setHfpActiveDevice(null);
-                    if (mActiveMediaProfile == PROFILE_NOT_DECIDED_YET) {
-                        mActiveMediaProfile = BluetoothProfile.HAP_CLIENT;
-                    }
-                    if (mActiveCallProfile == PROFILE_NOT_DECIDED_YET) {
-                        mActiveCallProfile = BluetoothProfile.HAP_CLIENT;
-                    }
                 }
-                return true;
+                return;
             }
         }
 
@@ -1112,35 +792,41 @@
 
         List<BluetoothDevice> connectedDevices = new ArrayList<>();
         connectedDevices.addAll(mLeAudioConnectedDevices);
-        boolean isMediaMode = isMediaMode(mAudioManager.getMode());
-        if (isMediaMode) {
-            if (a2dpFallbackDevice != null) {
-                connectedDevices.add(a2dpFallbackDevice);
-            }
-        } else {
-            if (headsetFallbackDevice != null) {
-                connectedDevices.add(headsetFallbackDevice);
-            }
+        switch (mAudioManager.getMode()) {
+            case AudioManager.MODE_NORMAL:
+                if (a2dpFallbackDevice != null) {
+                    connectedDevices.add(a2dpFallbackDevice);
+                }
+                break;
+            case AudioManager.MODE_RINGTONE:
+                if (headsetFallbackDevice != null && headsetService.isInbandRingingEnabled()) {
+                    connectedDevices.add(headsetFallbackDevice);
+                }
+                break;
+            default:
+                if (headsetFallbackDevice != null) {
+                    connectedDevices.add(headsetFallbackDevice);
+                }
         }
-
         BluetoothDevice device = dbManager.getMostRecentlyConnectedDevicesInList(connectedDevices);
         if (device != null) {
-            if (isMediaMode) {
+            if (mAudioManager.getMode() == AudioManager.MODE_NORMAL) {
                 if (Objects.equals(a2dpFallbackDevice, device)) {
                     if (DBG) {
                         Log.d(TAG, "set A2DP device active: " + device);
                     }
                     setA2dpActiveDevice(device);
-                    setLeAudioActiveDevice(null, true);
-                    mActiveMediaProfile = BluetoothProfile.A2DP;
+                    if (headsetFallbackDevice != null) {
+                        setHfpActiveDevice(device);
+                        setLeAudioActiveDevice(null);
+                    }
                 } else {
                     if (DBG) {
                         Log.d(TAG, "set LE audio device active: " + device);
                     }
                     setLeAudioActiveDevice(device);
-                    setA2dpActiveDevice(null, true);
+                    setA2dpActiveDevice(null);
                     setHfpActiveDevice(null);
-                    mActiveMediaProfile = BluetoothProfile.LE_AUDIO;
                 }
             } else {
                 if (Objects.equals(headsetFallbackDevice, device)) {
@@ -1148,21 +834,20 @@
                         Log.d(TAG, "set HFP device active: " + device);
                     }
                     setHfpActiveDevice(device);
-                    setLeAudioActiveDevice(null);
-                    mActiveCallProfile = BluetoothProfile.HEADSET;
+                    if (a2dpFallbackDevice != null) {
+                        setA2dpActiveDevice(a2dpFallbackDevice);
+                        setLeAudioActiveDevice(null);
+                    }
                 } else {
                     if (DBG) {
                         Log.d(TAG, "set LE audio device active: " + device);
                     }
                     setLeAudioActiveDevice(device);
-                    setA2dpActiveDevice(null, true);
+                    setA2dpActiveDevice(null);
                     setHfpActiveDevice(null);
-                    mActiveCallProfile = BluetoothProfile.LE_AUDIO;
                 }
             }
-            return true;
         }
-        return false;
     }
 
     private void resetState() {
@@ -1218,8 +903,6 @@
         if (DBG) {
             Log.d(TAG, "wiredAudioDeviceConnected");
         }
-        mActiveMediaProfile = PROFILE_USE_BUILTIN_AUDIO_DEVICE;
-        mActiveCallProfile = PROFILE_USE_BUILTIN_AUDIO_DEVICE;
         setA2dpActiveDevice(null);
         setHfpActiveDevice(null);
         setHearingAidActiveDevice(null);
diff --git a/android/app/src/com/android/bluetooth/hearingaid/HearingAidService.java b/android/app/src/com/android/bluetooth/hearingaid/HearingAidService.java
index 78afdb7..419e3c5 100644
--- a/android/app/src/com/android/bluetooth/hearingaid/HearingAidService.java
+++ b/android/app/src/com/android/bluetooth/hearingaid/HearingAidService.java
@@ -585,24 +585,13 @@
      * @return true on success, otherwise false
      */
     public boolean setActiveDevice(BluetoothDevice device) {
-        return setActiveDevice(device, false);
-    }
-
-    /**
-     * Set the active device.
-     * @param device the new active device
-     * @param hasFallbackDevice whether it has fallback device when the {@code device}
-     *                          is {@code null}.
-     * @return true on success, otherwise false
-     */
-    public boolean setActiveDevice(BluetoothDevice device, boolean hasFallbackDevice) {
         if (DBG) {
             Log.d(TAG, "setActiveDevice:" + device);
         }
         synchronized (mStateMachines) {
             if (device == null) {
                 if (mActiveDeviceHiSyncId != BluetoothHearingAid.HI_SYNC_ID_INVALID) {
-                    reportActiveDevice(null, hasFallbackDevice);
+                    reportActiveDevice(null);
                     mActiveDeviceHiSyncId = BluetoothHearingAid.HI_SYNC_ID_INVALID;
                 }
                 return true;
@@ -621,7 +610,7 @@
                     BluetoothHearingAid.HI_SYNC_ID_INVALID);
             if (deviceHiSyncId != mActiveDeviceHiSyncId) {
                 mActiveDeviceHiSyncId = deviceHiSyncId;
-                reportActiveDevice(device, false);
+                reportActiveDevice(device);
             }
         }
         return true;
@@ -772,7 +761,7 @@
      * Report the active device change to the active device manager and the media framework.
      * @param device the new active device; or null if no active device
      */
-    private void reportActiveDevice(BluetoothDevice device, boolean hasFallbackDevice) {
+    private void reportActiveDevice(BluetoothDevice device) {
         if (DBG) {
             Log.d(TAG, "reportActiveDevice(" + device + ")");
         }
@@ -783,7 +772,14 @@
                 BluetoothProfile.HEARING_AID, mAdapterService.obfuscateAddress(device),
                 mAdapterService.getMetricId(device));
 
-        boolean stopAudio = device == null && !hasFallbackDevice;
+        Intent intent = new Intent(BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED);
+        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
+        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
+                | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+        sendBroadcast(intent, BLUETOOTH_CONNECT, Utils.getTempAllowlistBroadcastOptions());
+
+        boolean stopAudio = device == null
+                && (getConnectionState(mPreviousAudioDevice) != BluetoothProfile.STATE_CONNECTED);
         if (DBG) {
             Log.d(TAG, "Hearing Aid audio: " + mPreviousAudioDevice + " -> " + device
                     + ". Stop audio: " + stopAudio);
@@ -899,7 +895,7 @@
             }
         }
         if (fromState == BluetoothProfile.STATE_CONNECTED && getConnectedDevices().isEmpty()) {
-            // When disconnected, ActiveDeviceManager will call setActiveDevice(null)
+            setActiveDevice(null);
             long myHiSyncId = getHiSyncId(device);
             mHiSyncIdConnectedMap.put(myHiSyncId, false);
         }
diff --git a/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java b/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java
index deb917b..e3b6af4 100644
--- a/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java
+++ b/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java
@@ -164,6 +164,7 @@
     private final Map<BluetoothDevice, Integer> mDeviceAudioLocationMap = new ConcurrentHashMap<>();
 
     private BroadcastReceiver mBondStateChangedReceiver;
+    private BroadcastReceiver mConnectionStateChangedReceiver;
     private BroadcastReceiver mMuteStateChangedReceiver;
     private int mStoredRingerMode = -1;
     private Handler mHandler = new Handler(Looper.getMainLooper());
@@ -234,6 +235,10 @@
         mBondStateChangedReceiver = new BondStateChangedReceiver();
         registerReceiver(mBondStateChangedReceiver, filter);
         filter = new IntentFilter();
+        filter.addAction(BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED);
+        mConnectionStateChangedReceiver = new ConnectionStateChangedReceiver();
+        registerReceiver(mConnectionStateChangedReceiver, filter);
+        filter = new IntentFilter();
         filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
         mMuteStateChangedReceiver = new MuteStateChangedReceiver();
         registerReceiver(mMuteStateChangedReceiver, filter);
@@ -245,7 +250,7 @@
 
         // Initialize Broadcast native interface
         if ((mAdapterService.getSupportedProfilesBitMask()
-                & (1 << BluetoothProfile.LE_AUDIO_BROADCAST)) != 0) {
+                    & (1 << BluetoothProfile.LE_AUDIO_BROADCAST)) != 0) {
             Log.i(TAG, "Init Le Audio broadcaster");
             mBroadcastCallbacks = new RemoteCallbackList<IBluetoothLeBroadcastCallback>();
             mLeAudioBroadcasterNativeInterface = Objects.requireNonNull(
@@ -338,6 +343,8 @@
         // Unregister broadcast receivers
         unregisterReceiver(mBondStateChangedReceiver);
         mBondStateChangedReceiver = null;
+        unregisterReceiver(mConnectionStateChangedReceiver);
+        mConnectionStateChangedReceiver = null;
         unregisterReceiver(mMuteStateChangedReceiver);
         mMuteStateChangedReceiver = null;
 
@@ -818,6 +825,12 @@
         if (!Objects.equals(device, previousInDevice)
                 || (oldSupportedByDeviceInput != newSupportedByDeviceInput)) {
             mActiveAudioInDevice = newSupportedByDeviceInput ? device : null;
+            if (DBG) {
+                Log.d(TAG, " handleBluetoothActiveDeviceChanged  previousInDevice: "
+                        + previousInDevice + ", mActiveAudioInDevice" + mActiveAudioInDevice
+                        + " isLeOutput: false");
+            }
+
             return true;
         }
         Log.d(TAG, "updateActiveInDevice: Nothing to do.");
@@ -870,6 +883,11 @@
         if (!Objects.equals(device, previousOutDevice)
                 || (oldSupportedByDeviceOutput != newSupportedByDeviceOutput)) {
             mActiveAudioOutDevice = newSupportedByDeviceOutput ? device : null;
+            if (DBG) {
+                Log.d(TAG, " handleBluetoothActiveDeviceChanged previousOutDevice: "
+                        + previousOutDevice + ", mActiveOutDevice: " + mActiveAudioOutDevice
+                        + " isLeOutput: true");
+            }
             return true;
         }
         Log.d(TAG, "updateActiveOutDevice: Nothing to do.");
@@ -929,12 +947,6 @@
      */
     private boolean updateActiveDevices(Integer groupId, Integer oldSupportedAudioDirections,
             Integer newSupportedAudioDirections, boolean isActive) {
-        return updateActiveDevices(groupId, oldSupportedAudioDirections,
-                newSupportedAudioDirections, isActive, false);
-    }
-
-    private boolean updateActiveDevices(Integer groupId, Integer oldSupportedAudioDirections,
-            Integer newSupportedAudioDirections, boolean isActive, boolean hasFallbackDevice) {
         BluetoothDevice device = null;
         BluetoothDevice previousActiveOutDevice = mActiveAudioOutDevice;
         BluetoothDevice previousActiveInDevice = mActiveAudioInDevice;
@@ -943,19 +955,19 @@
             device = getFirstDeviceFromGroup(groupId);
         }
 
-        boolean isActiveOutDeviceChanged = updateActiveOutDevice(device, groupId,
+        boolean isNewActiveOutDevice = updateActiveOutDevice(device, groupId,
                 oldSupportedAudioDirections, newSupportedAudioDirections);
-        boolean isActiveInDeviceChanged = updateActiveInDevice(device, groupId,
+        boolean isNewActiveInDevice = updateActiveInDevice(device, groupId,
                 oldSupportedAudioDirections, newSupportedAudioDirections);
 
         if (DBG) {
-            Log.d(TAG, " isActiveOutDeviceUpdated: " + isActiveOutDeviceChanged + ", "
-                    + mActiveAudioOutDevice + ", isActiveInDeviceUpdated: "
-                    + isActiveInDeviceChanged + ", " + mActiveAudioInDevice);
+            Log.d(TAG, " isNewActiveOutDevice: " + isNewActiveOutDevice + ", "
+                    + mActiveAudioOutDevice + ", isNewActiveInDevice: " + isNewActiveInDevice
+                    + ", " + mActiveAudioInDevice);
         }
 
         /* Active device changed, there is need to inform about new active LE Audio device */
-        if (isActiveOutDeviceChanged || isActiveInDeviceChanged) {
+        if (isNewActiveOutDevice || isNewActiveInDevice) {
             /* Register for new device connection/disconnection in Audio Manager */
             if (mActiveAudioOutDevice != null || mActiveAudioInDevice != null) {
                 /* Register for any device connection in case if any of devices become connected */
@@ -968,14 +980,14 @@
             }
         }
 
-        if (isActiveOutDeviceChanged) {
+        if (isNewActiveOutDevice) {
             int volume = IBluetoothVolumeControl.VOLUME_CONTROL_UNKNOWN_VOLUME;
 
             if (mActiveAudioOutDevice != null) {
                 volume = getAudioDeviceGroupVolume(groupId);
             }
 
-            final boolean suppressNoisyIntent = hasFallbackDevice || (mActiveAudioOutDevice != null)
+            final boolean suppressNoisyIntent = (mActiveAudioOutDevice != null)
                     || (getConnectionState(previousActiveOutDevice)
                     == BluetoothProfile.STATE_CONNECTED);
 
@@ -983,7 +995,7 @@
                     previousActiveOutDevice, getLeAudioOutputProfile(suppressNoisyIntent, volume));
         }
 
-        if (isActiveInDeviceChanged) {
+        if (isNewActiveInDevice) {
             mAudioManager.handleBluetoothActiveDeviceChanged(mActiveAudioInDevice,
                     previousActiveInDevice, BluetoothProfileConnectionInfo.createLeAudioInfo(false,
                             false));
@@ -996,10 +1008,6 @@
      * Set the active device group.
      */
     private void setActiveGroupWithDevice(BluetoothDevice device) {
-        setActiveGroupWithDevice(device, false);
-    }
-
-    private void setActiveGroupWithDevice(BluetoothDevice device, boolean hasFallbackDevice) {
         int groupId = LE_AUDIO_GROUP_ID_INVALID;
 
         if (device != null) {
@@ -1030,7 +1038,7 @@
              * However we would like to notify audio framework that LeAudio is not
              * active anymore and does not want to get more audio data.
              */
-            handleGroupTransitToInactive(currentlyActiveGroupId, hasFallbackDevice);
+            handleGroupTransitToInactive(currentlyActiveGroupId);
         }
     }
 
@@ -1041,21 +1049,9 @@
      * @return true on success, otherwise false
      */
     public boolean setActiveDevice(BluetoothDevice device) {
-        return setActiveDevice(device, false);
-    }
-
-    /**
-     * Set the active group represented by device.
-     *
-     * @param device the new active device
-     * @param hasFallbackDevice whether it has fallback device when the {@code device}
-     *                          is {@code null}.
-     * @return true on success, otherwise false
-     */
-    public boolean setActiveDevice(BluetoothDevice device, boolean hasFallbackDevice) {
         /* Clear active group */
         if (device == null) {
-            setActiveGroupWithDevice(device, hasFallbackDevice);
+            setActiveGroupWithDevice(device);
             return true;
         }
         if (getConnectionState(device) != BluetoothProfile.STATE_CONNECTED) {
@@ -1211,7 +1207,7 @@
         }
     }
 
-    private void handleGroupTransitToInactive(int groupId, boolean hasFallbackDevice) {
+    private void handleGroupTransitToInactive(int groupId) {
         synchronized (mGroupLock) {
             LeAudioGroupDescriptor descriptor = getGroupDescriptor(groupId);
             if (descriptor == null || !descriptor.mIsActive) {
@@ -1221,7 +1217,7 @@
 
             descriptor.mIsActive = false;
             updateActiveDevices(groupId, descriptor.mDirection, AUDIO_DIRECTION_NONE,
-                    descriptor.mIsActive, hasFallbackDevice);
+                    descriptor.mIsActive);
             /* Clear lost devices */
             if (DBG) Log.d(TAG, "Clear for group: " + groupId);
             clearLostDevicesWhileStreaming(descriptor);
@@ -1394,8 +1390,9 @@
             LeAudioGroupDescriptor descriptor = getGroupDescriptor(groupId);
             if (descriptor != null) {
                 if (descriptor.mIsActive) {
-                    descriptor.mIsActive = updateActiveDevices(
-                            groupId, descriptor.mDirection, direction, descriptor.mIsActive);
+                    descriptor.mIsActive =
+                            updateActiveDevices(groupId, descriptor.mDirection, direction,
+                            descriptor.mIsActive);
                     if (!descriptor.mIsActive) {
                         notifyGroupStatusChanged(groupId, BluetoothLeAudio.GROUP_STATUS_INACTIVE);
                     }
@@ -1425,7 +1422,7 @@
                     break;
                 }
                 case LeAudioStackEvent.GROUP_STATUS_INACTIVE: {
-                    handleGroupTransitToInactive(groupId, false);
+                    handleGroupTransitToInactive(groupId);
                     break;
                 }
                 case LeAudioStackEvent.GROUP_STATUS_TURNED_IDLE_DURING_CALL: {
@@ -1650,92 +1647,100 @@
         return result;
     }
 
-    /**
-     * Handles the connection of LE Audio device.
-     *
-     * @param device THe device that is connected.
-     */
-    public synchronized void deviceConnected(BluetoothDevice device) {
-        int myGroupId = getGroupId(device);
-        if (myGroupId == LE_AUDIO_GROUP_ID_INVALID
-                || getConnectedPeerDevices(myGroupId).size() == 1) {
-            // Log LE Audio connection event if we are the first device in a set
-            // Or when the GroupId has not been found
-            // MetricsLogger.logProfileConnectionEvent(
-            //         BluetoothMetricsProto.ProfileId.LE_AUDIO);
+    @VisibleForTesting
+    synchronized void connectionStateChanged(BluetoothDevice device, int fromState, int toState) {
+        if ((device == null) || (fromState == toState)) {
+            Log.e(TAG, "connectionStateChanged: unexpected invocation. device=" + device
+                    + " fromState=" + fromState + " toState=" + toState);
+            return;
         }
-
-        LeAudioGroupDescriptor descriptor = getGroupDescriptor(myGroupId);
-        if (descriptor != null) {
-            descriptor.mIsConnected = true;
-        } else {
-            Log.e(TAG, "no descriptors for group: " + myGroupId);
-        }
-
-        McpService mcpService = mServiceFactory.getMcpService();
-        if (mcpService != null) {
-            mcpService.setDeviceAuthorized(device, true);
-        }
-    }
-
-    /**
-     * Handle the disconnection of LE Audio device.
-     *
-     * @param device The device that is disconnected
-     * @param hasFallbackDevice whether it has fallback device when the {@code device}
-     *                          is {@code null}.
-     */
-    public synchronized void deviceDisconnected(BluetoothDevice device, boolean hasFallbackDevice) {
-        // If unbond, remove the state machine
-        int bondState = mAdapterService.getBondState(device);
-        if (bondState == BluetoothDevice.BOND_NONE) {
-            if (DBG) {
-                Log.d(TAG, device + " is unbond. Remove state machine");
+        if (toState == BluetoothProfile.STATE_CONNECTED) {
+            int myGroupId = getGroupId(device);
+            if (myGroupId == LE_AUDIO_GROUP_ID_INVALID
+                    || getConnectedPeerDevices(myGroupId).size() == 1) {
+                // Log LE Audio connection event if we are the first device in a set
+                // Or when the GroupId has not been found
+                // MetricsLogger.logProfileConnectionEvent(
+                //         BluetoothMetricsProto.ProfileId.LE_AUDIO);
             }
-            removeStateMachine(device);
-        }
 
-        McpService mcpService = mServiceFactory.getMcpService();
-        if (mcpService != null) {
-            mcpService.setDeviceAuthorized(device, false);
-        }
+            LeAudioGroupDescriptor descriptor = getGroupDescriptor(myGroupId);
+            if (descriptor != null) {
+                descriptor.mIsConnected = true;
+            } else {
+                Log.e(TAG, "no descriptors for group: " + myGroupId);
+            }
 
-        int myGroupId = getGroupId(device);
-        LeAudioGroupDescriptor descriptor = getGroupDescriptor(myGroupId);
-        if (descriptor == null) {
-            Log.e(TAG, "no descriptors for group: " + myGroupId);
-            return;
+            McpService mcpService = mServiceFactory.getMcpService();
+            if (mcpService != null) {
+                mcpService.setDeviceAuthorized(device, true);
+            }
         }
+        // Check if the device is disconnected - if unbond, remove the state machine
+        if (toState == BluetoothProfile.STATE_DISCONNECTED) {
+            int bondState = mAdapterService.getBondState(device);
+            if (bondState == BluetoothDevice.BOND_NONE) {
+                if (DBG) {
+                    Log.d(TAG, device + " is unbond. Remove state machine");
+                }
+                removeStateMachine(device);
+            }
 
-        List<BluetoothDevice> connectedDevices = getConnectedPeerDevices(myGroupId);
-        /* Let's check if the last connected device is really connected */
-        if (connectedDevices.size() == 1 && Objects.equals(
-                connectedDevices.get(0), descriptor.mLostLeadDeviceWhileStreaming)) {
-            clearLostDevicesWhileStreaming(descriptor);
-            return;
-        }
+            McpService mcpService = mServiceFactory.getMcpService();
+            if (mcpService != null) {
+                mcpService.setDeviceAuthorized(device, false);
+            }
 
-        if (getConnectedPeerDevices(myGroupId).isEmpty()) {
-            descriptor.mIsConnected = false;
+            int myGroupId = getGroupId(device);
+            LeAudioGroupDescriptor descriptor = getGroupDescriptor(myGroupId);
+            if (descriptor == null) {
+                Log.e(TAG, "no descriptors for group: " + myGroupId);
+                return;
+            }
+
+            List<BluetoothDevice> connectedDevices = getConnectedPeerDevices(myGroupId);
+            /* Let's check if the last connected device is really connected */
+            if (connectedDevices.size() == 1 && Objects.equals(
+                    connectedDevices.get(0), descriptor.mLostLeadDeviceWhileStreaming)) {
+                clearLostDevicesWhileStreaming(descriptor);
+                return;
+            }
+
+            if (getConnectedPeerDevices(myGroupId).isEmpty()) {
+                descriptor.mIsConnected = false;
+                if (descriptor.mIsActive) {
+                    /* Notify Native layer */
+                    setActiveDevice(null);
+                    descriptor.mIsActive = false;
+                    /* Update audio framework */
+                    updateActiveDevices(myGroupId,
+                            descriptor.mDirection,
+                            descriptor.mDirection,
+                            descriptor.mIsActive);
+                    return;
+                }
+            }
+
             if (descriptor.mIsActive) {
-                /* Notify Native layer */
-                setActiveDevice(null);
-                descriptor.mIsActive = false;
-                /* Update audio framework */
                 updateActiveDevices(myGroupId,
                         descriptor.mDirection,
                         descriptor.mDirection,
-                        descriptor.mIsActive,
-                        hasFallbackDevice);
-                return;
+                        descriptor.mIsActive);
             }
         }
+    }
 
-        if (descriptor.mIsActive) {
-            updateActiveDevices(myGroupId,
-                    descriptor.mDirection,
-                    descriptor.mDirection,
-                    descriptor.mIsActive);
+    private class ConnectionStateChangedReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (!BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED
+                    .equals(intent.getAction())) {
+                return;
+            }
+            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+            int toState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
+            int fromState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, -1);
+            connectionStateChanged(device, fromState, toState);
         }
     }
 
diff --git a/android/app/src/com/android/bluetooth/map/BluetoothMapContentObserver.java b/android/app/src/com/android/bluetooth/map/BluetoothMapContentObserver.java
index 31ba0b1..a7931c0 100644
--- a/android/app/src/com/android/bluetooth/map/BluetoothMapContentObserver.java
+++ b/android/app/src/com/android/bluetooth/map/BluetoothMapContentObserver.java
@@ -1420,6 +1420,7 @@
                         int type = c.getInt(c.getColumnIndex(Sms.TYPE));
                         int threadId = c.getInt(c.getColumnIndex(Sms.THREAD_ID));
                         int read = c.getInt(c.getColumnIndex(Sms.READ));
+                        long timestamp = c.getLong(c.getColumnIndex(Sms.DATE));
 
                         Msg msg = getMsgListSms().remove(id);
 
@@ -1427,6 +1428,10 @@
                          * a message deleted and/or MessageShift for messages deleted by the MCE. */
 
                         if (msg == null) {
+                            if (BluetoothMapUtils.isDateTimeOlderThanOneYear(timestamp)) {
+                                // Skip sending new message events older than one year
+                                continue;
+                            }
                             /* New message */
                             msg = new Msg(id, type, threadId, read);
                             msgListSms.put(id, msg);
@@ -1435,8 +1440,7 @@
                             if (mTransmitEvents && // extract contact details only if needed
                                     mMapEventReportVersion
                                             > BluetoothMapUtils.MAP_EVENT_REPORT_V10) {
-                                String date = BluetoothMapUtils.getDateTimeString(
-                                        c.getLong(c.getColumnIndex(Sms.DATE)));
+                                String date = BluetoothMapUtils.getDateTimeString(timestamp);
                                 String subject = c.getString(c.getColumnIndex(Sms.BODY));
                                 if (subject == null) {
                                     subject = "";
@@ -1583,6 +1587,7 @@
                         // TODO: Go through code to see if we have an issue with mismatch in types
                         //       for threadId. Seems to be a long in DB??
                         int read = c.getInt(c.getColumnIndex(Mms.READ));
+                        long timestamp = c.getLong(c.getColumnIndex(Mms.DATE));
 
                         Msg msg = getMsgListMms().remove(id);
 
@@ -1591,6 +1596,10 @@
                          * MCE.*/
 
                         if (msg == null) {
+                            if (BluetoothMapUtils.isDateTimeOlderThanOneYear(timestamp)) {
+                                // Skip sending new message events older than one year
+                                continue;
+                            }
                             /* New message - only notify on retrieve conf */
                             listChanged = true;
                             if (getMmsFolderName(type).equalsIgnoreCase(
@@ -1604,8 +1613,7 @@
                             if (mTransmitEvents && // extract contact details only if needed
                                     mMapEventReportVersion
                                             != BluetoothMapUtils.MAP_EVENT_REPORT_V10) {
-                                String date = BluetoothMapUtils.getDateTimeString(
-                                        c.getLong(c.getColumnIndex(Mms.DATE)));
+                                String date = BluetoothMapUtils.getDateTimeString(timestamp);
                                 String subject = c.getString(c.getColumnIndex(Mms.SUBJECT));
                                 if (subject == null || subject.length() == 0) {
                                     /* Get subject from mms text body parts - if any exists */
diff --git a/android/app/src/com/android/bluetooth/map/BluetoothMapUtils.java b/android/app/src/com/android/bluetooth/map/BluetoothMapUtils.java
index a3710a3..7d7047f 100644
--- a/android/app/src/com/android/bluetooth/map/BluetoothMapUtils.java
+++ b/android/app/src/com/android/bluetooth/map/BluetoothMapUtils.java
@@ -677,6 +677,21 @@
         return format.format(cal.getTime());
     }
 
+    static boolean isDateTimeOlderThanOneYear(long timestamp) {
+        Calendar cal = Calendar.getInstance();
+        cal.setTimeInMillis(timestamp);
+        Calendar oneYearAgo = Calendar.getInstance();
+        oneYearAgo.add(Calendar.YEAR, -1);
+        if (cal.compareTo(oneYearAgo) > 0) {
+            if (V) {
+                Log.v(TAG, "isDateTimeOlderThanOneYear timestamp : " + timestamp
+                        + " oneYearAgo: " + oneYearAgo);
+            }
+            return true;
+        }
+        return false;
+    }
+
     static void savePeerSupportUtcTimeStamp(int remoteFeatureMask) {
         if ((remoteFeatureMask & MAP_FEATURE_DEFINED_TIMESTAMP_FORMAT_BIT)
                 == MAP_FEATURE_DEFINED_TIMESTAMP_FORMAT_BIT) {
diff --git a/android/app/src/com/android/bluetooth/mcp/MediaControlGattService.java b/android/app/src/com/android/bluetooth/mcp/MediaControlGattService.java
index 7b44d0c..0f1fef7 100644
--- a/android/app/src/com/android/bluetooth/mcp/MediaControlGattService.java
+++ b/android/app/src/com/android/bluetooth/mcp/MediaControlGattService.java
@@ -24,6 +24,8 @@
 import static android.bluetooth.BluetoothGattCharacteristic.PROPERTY_WRITE;
 import static android.bluetooth.BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE;
 
+import static java.util.Map.entry;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.bluetooth.BluetoothDevice;
@@ -41,7 +43,9 @@
 import android.util.Log;
 import android.util.Pair;
 
+import com.android.bluetooth.a2dp.A2dpService;
 import com.android.bluetooth.btservice.AdapterService;
+import com.android.bluetooth.hearingaid.HearingAidService;
 import com.android.bluetooth.le_audio.LeAudioService;
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -889,6 +893,12 @@
         }
 
         if (req.getOpcode() == Request.Opcodes.PLAY) {
+            if (mAdapterService.getActiveDevices(BluetoothProfile.A2DP).size() > 0) {
+                A2dpService.getA2dpService().setActiveDevice(null);
+            }
+            if (mAdapterService.getActiveDevices(BluetoothProfile.HEARING_AID).size() > 0) {
+                HearingAidService.getHearingAidService().setActiveDevice(null);
+            }
             if (mLeAudioService == null) {
                 mLeAudioService = LeAudioService.getLeAudioService();
             }
diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/ActiveDeviceManagerTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/ActiveDeviceManagerTest.java
index abe94fb..0854962 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/btservice/ActiveDeviceManagerTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/ActiveDeviceManagerTest.java
@@ -17,11 +17,10 @@
 package com.android.bluetooth.btservice;
 
 import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyBoolean;
-import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.isNull;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -60,6 +59,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
 @MediumTest
 @RunWith(AndroidJUnit4.class)
@@ -86,7 +86,6 @@
     @Mock private LeAudioService mLeAudioService;
     @Mock private AudioManager mAudioManager;
     @Mock private DatabaseManager mDatabaseManager;
-    private AudioManager.OnModeChangedListener mAudioModeChangedListener;
 
     @Before
     public void setUp() throws Exception {
@@ -99,10 +98,6 @@
         MockitoAnnotations.initMocks(this);
         TestUtils.setAdapterService(mAdapterService);
 
-        doAnswer(invocation -> {
-            mAudioModeChangedListener = invocation.getArgument(1);
-            return null;
-        }).when(mAudioManager).addOnModeChangedListener(any(), any());
         when(mAdapterService.getSystemService(Context.AUDIO_SERVICE)).thenReturn(mAudioManager);
         when(mAdapterService.getSystemServiceName(AudioManager.class))
                 .thenReturn(Context.AUDIO_SERVICE);
@@ -127,20 +122,24 @@
         mDeviceConnectionStack = new ArrayList<>();
         mMostRecentDevice = null;
 
-        when(mA2dpService.setActiveDevice(any(), anyBoolean())).thenReturn(true);
+        when(mA2dpService.setActiveDevice(any())).thenReturn(true);
         when(mHeadsetService.setActiveDevice(any())).thenReturn(true);
-        when(mHearingAidService.setActiveDevice(any(), anyBoolean())).thenReturn(true);
-        when(mLeAudioService.setActiveDevice(any(), anyBoolean())).thenReturn(true);
+        when(mHearingAidService.setActiveDevice(any())).thenReturn(true);
+        when(mLeAudioService.setActiveDevice(any())).thenReturn(true);
 
         when(mA2dpService.getFallbackDevice()).thenAnswer(invocation -> {
-            int index = Math.max(mDeviceConnectionStack.indexOf(mA2dpDevice),
-                    mDeviceConnectionStack.indexOf(mA2dpHeadsetDevice));
-            return (index == -1) ? null : mDeviceConnectionStack.get(index);
+            if (!mDeviceConnectionStack.isEmpty() && Objects.equals(mA2dpDevice,
+                    mDeviceConnectionStack.get(mDeviceConnectionStack.size() - 1))) {
+                return mA2dpDevice;
+            }
+            return null;
         });
         when(mHeadsetService.getFallbackDevice()).thenAnswer(invocation -> {
-            int index = Math.max(mDeviceConnectionStack.indexOf(mHeadsetDevice),
-                    mDeviceConnectionStack.indexOf(mA2dpHeadsetDevice));
-            return (index == -1) ? null : mDeviceConnectionStack.get(index);
+            if (!mDeviceConnectionStack.isEmpty() && Objects.equals(mHeadsetDevice,
+                    mDeviceConnectionStack.get(mDeviceConnectionStack.size() - 1))) {
+                return mHeadsetDevice;
+            }
+            return null;
         });
         when(mDatabaseManager.getMostRecentlyConnectedDevicesInList(any())).thenAnswer(
                 invocation -> {
@@ -178,7 +177,7 @@
     @Test
     public void onlyA2dpConnected_setA2dpActive() {
         a2dpConnected(mA2dpDevice);
-        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpDevice, false);
+        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpDevice);
     }
 
     /**
@@ -187,10 +186,10 @@
     @Test
     public void secondA2dpConnected_setSecondA2dpActive() {
         a2dpConnected(mA2dpDevice);
-        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpDevice, false);
+        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpDevice);
 
         a2dpConnected(mA2dpHeadsetDevice);
-        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpHeadsetDevice, false);
+        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpHeadsetDevice);
     }
 
     /**
@@ -199,10 +198,10 @@
     @Test
     public void lastA2dpDisconnected_clearA2dpActive() {
         a2dpConnected(mA2dpDevice);
-        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpDevice, false);
+        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpDevice);
 
         a2dpDisconnected(mA2dpDevice);
-        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(null, false);
+        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(isNull());
     }
 
     /**
@@ -211,15 +210,15 @@
     @Test
     public void a2dpActiveDeviceSelected_setActive() {
         a2dpConnected(mA2dpDevice);
-        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpDevice, false);
+        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpDevice);
 
         a2dpConnected(mA2dpHeadsetDevice);
-        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpHeadsetDevice, false);
+        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpHeadsetDevice);
 
         a2dpActiveDeviceChanged(mA2dpDevice);
         // Don't call mA2dpService.setActiveDevice()
         TestUtils.waitForLooperToFinishScheduledTask(mActiveDeviceManager.getHandlerLooper());
-        verify(mA2dpService).setActiveDevice(mA2dpDevice, false);
+        verify(mA2dpService, times(1)).setActiveDevice(mA2dpDevice);
         Assert.assertEquals(mA2dpDevice, mActiveDeviceManager.getA2dpActiveDevice());
     }
 
@@ -230,14 +229,14 @@
     @Test
     public void a2dpSecondDeviceDisconnected_fallbackDeviceActive() {
         a2dpConnected(mA2dpDevice);
-        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpDevice, false);
+        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpDevice);
 
         a2dpConnected(mSecondaryAudioDevice);
-        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mSecondaryAudioDevice, false);
+        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mSecondaryAudioDevice);
 
         Mockito.clearInvocations(mA2dpService);
         a2dpDisconnected(mSecondaryAudioDevice);
-        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpDevice, false);
+        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpDevice);
     }
 
     /**
@@ -245,8 +244,6 @@
      */
     @Test
     public void onlyHeadsetConnected_setHeadsetActive() {
-        when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_IN_CALL);
-
         headsetConnected(mHeadsetDevice);
         verify(mHeadsetService, timeout(TIMEOUT_MS)).setActiveDevice(mHeadsetDevice);
     }
@@ -256,8 +253,6 @@
      */
     @Test
     public void secondHeadsetConnected_setSecondHeadsetActive() {
-        when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_IN_CALL);
-
         headsetConnected(mHeadsetDevice);
         verify(mHeadsetService, timeout(TIMEOUT_MS)).setActiveDevice(mHeadsetDevice);
 
@@ -270,8 +265,6 @@
      */
     @Test
     public void lastHeadsetDisconnected_clearHeadsetActive() {
-        when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_IN_CALL);
-
         headsetConnected(mHeadsetDevice);
         verify(mHeadsetService, timeout(TIMEOUT_MS)).setActiveDevice(mHeadsetDevice);
 
@@ -284,8 +277,6 @@
      */
     @Test
     public void headsetActiveDeviceSelected_setActive() {
-        when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_IN_CALL);
-
         headsetConnected(mHeadsetDevice);
         verify(mHeadsetService, timeout(TIMEOUT_MS)).setActiveDevice(mHeadsetDevice);
 
@@ -295,7 +286,7 @@
         headsetActiveDeviceChanged(mHeadsetDevice);
         // Don't call mHeadsetService.setActiveDevice()
         TestUtils.waitForLooperToFinishScheduledTask(mActiveDeviceManager.getHandlerLooper());
-        verify(mHeadsetService).setActiveDevice(mHeadsetDevice);
+        verify(mHeadsetService, times(1)).setActiveDevice(mHeadsetDevice);
         Assert.assertEquals(mHeadsetDevice, mActiveDeviceManager.getHfpActiveDevice());
     }
 
@@ -319,33 +310,6 @@
     }
 
     /**
-     * Test setActiveDevice(null) for both A2dpService and HeadsetService are called when an
-     * activated combo (A2DP + Headset) device is disconnected while in call.
-     */
-    @Test
-    public void a2dpHeadsetDisconnected_callsSetActiveDeviceNull() {
-        when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_NORMAL);
-        // A2dpHeadset connected
-        headsetConnected(mA2dpHeadsetDevice);
-        a2dpConnected(mA2dpHeadsetDevice);
-        // Verify activation of A2DP in media mode
-        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpHeadsetDevice, false);
-
-        // Mode changed to call mode
-        when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_IN_CALL);
-        mAudioModeChangedListener.onModeChanged(AudioManager.MODE_IN_CALL);
-        // Verify activation of HFP in call mode
-        verify(mHeadsetService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpHeadsetDevice);
-
-        // A2dpHeadset disconnected
-        headsetDisconnected(mA2dpHeadsetDevice);
-        a2dpDisconnected(mA2dpHeadsetDevice);
-        // Verify setActiveDevice(null) called
-        verify(mHeadsetService, timeout(TIMEOUT_MS)).setActiveDevice(null);
-        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(null, false);
-    }
-
-    /**
      * A combo (A2DP + Headset) device is connected. Then a Hearing Aid is connected.
      */
     @Test
@@ -355,11 +319,11 @@
 
         a2dpConnected(mA2dpHeadsetDevice);
         headsetConnected(mA2dpHeadsetDevice);
-        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpHeadsetDevice, false);
+        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpHeadsetDevice);
         verify(mHeadsetService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpHeadsetDevice);
 
         hearingAidActiveDeviceChanged(mHearingAidDevice);
-        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(null, true);
+        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(isNull());
         verify(mHeadsetService, timeout(TIMEOUT_MS)).setActiveDevice(isNull());
     }
 
@@ -376,7 +340,7 @@
         headsetConnected(mA2dpHeadsetDevice);
 
         TestUtils.waitForLooperToFinishScheduledTask(mActiveDeviceManager.getHandlerLooper());
-        verify(mA2dpService, never()).setActiveDevice(mA2dpHeadsetDevice, false);
+        verify(mA2dpService, never()).setActiveDevice(mA2dpHeadsetDevice);
         verify(mHeadsetService, never()).setActiveDevice(mA2dpHeadsetDevice);
     }
 
@@ -393,9 +357,9 @@
         a2dpActiveDeviceChanged(mA2dpHeadsetDevice);
 
         TestUtils.waitForLooperToFinishScheduledTask(mActiveDeviceManager.getHandlerLooper());
-        verify(mHearingAidService).setActiveDevice(null, true);
+        verify(mHearingAidService).setActiveDevice(isNull());
         // Don't call mA2dpService.setActiveDevice()
-        verify(mA2dpService, never()).setActiveDevice(mA2dpHeadsetDevice, false);
+        verify(mA2dpService, never()).setActiveDevice(mA2dpHeadsetDevice);
         Assert.assertEquals(mA2dpHeadsetDevice, mActiveDeviceManager.getA2dpActiveDevice());
         Assert.assertEquals(null, mActiveDeviceManager.getHearingAidActiveDevice());
     }
@@ -413,7 +377,7 @@
         headsetActiveDeviceChanged(mA2dpHeadsetDevice);
 
         TestUtils.waitForLooperToFinishScheduledTask(mActiveDeviceManager.getHandlerLooper());
-        verify(mHearingAidService).setActiveDevice(null, true);
+        verify(mHearingAidService).setActiveDevice(isNull());
         // Don't call mHeadsetService.setActiveDevice()
         verify(mHeadsetService, never()).setActiveDevice(mA2dpHeadsetDevice);
         Assert.assertEquals(mA2dpHeadsetDevice, mActiveDeviceManager.getHfpActiveDevice());
@@ -426,7 +390,7 @@
     @Test
     public void onlyLeAudioConnected_setHeadsetActive() {
         leAudioConnected(mLeAudioDevice);
-        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(mLeAudioDevice, false);
+        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(mLeAudioDevice);
     }
 
     /**
@@ -435,10 +399,10 @@
     @Test
     public void secondLeAudioConnected_setSecondLeAudioActive() {
         leAudioConnected(mLeAudioDevice);
-        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(mLeAudioDevice, false);
+        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(mLeAudioDevice);
 
         leAudioConnected(mSecondaryAudioDevice);
-        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(mSecondaryAudioDevice, false);
+        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(mSecondaryAudioDevice);
     }
 
     /**
@@ -447,10 +411,10 @@
     @Test
     public void lastLeAudioDisconnected_clearLeAudioActive() {
         leAudioConnected(mLeAudioDevice);
-        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(mLeAudioDevice, false);
+        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(mLeAudioDevice);
 
         leAudioDisconnected(mLeAudioDevice);
-        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(null, false);
+        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(isNull());
     }
 
     /**
@@ -459,15 +423,15 @@
     @Test
     public void leAudioActiveDeviceSelected_setActive() {
         leAudioConnected(mLeAudioDevice);
-        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(mLeAudioDevice, false);
+        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(mLeAudioDevice);
 
         leAudioConnected(mSecondaryAudioDevice);
-        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(mSecondaryAudioDevice, false);
+        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(mSecondaryAudioDevice);
 
         leAudioActiveDeviceChanged(mLeAudioDevice);
         // Don't call mLeAudioService.setActiveDevice()
         TestUtils.waitForLooperToFinishScheduledTask(mActiveDeviceManager.getHandlerLooper());
-        verify(mLeAudioService).setActiveDevice(mLeAudioDevice, false);
+        verify(mLeAudioService, times(1)).setActiveDevice(mLeAudioDevice);
         Assert.assertEquals(mLeAudioDevice, mActiveDeviceManager.getLeAudioActiveDevice());
     }
 
@@ -478,14 +442,14 @@
     @Test
     public void leAudioSecondDeviceDisconnected_fallbackDeviceActive() {
         leAudioConnected(mLeAudioDevice);
-        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(mLeAudioDevice, false);
+        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(mLeAudioDevice);
 
         leAudioConnected(mSecondaryAudioDevice);
-        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(mSecondaryAudioDevice, false);
+        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(mSecondaryAudioDevice);
 
         Mockito.clearInvocations(mLeAudioService);
         leAudioDisconnected(mSecondaryAudioDevice);
-        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(mLeAudioDevice, false);
+        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(mLeAudioDevice);
     }
 
     /**
@@ -498,11 +462,11 @@
 
         a2dpConnected(mA2dpHeadsetDevice);
         headsetConnected(mA2dpHeadsetDevice);
-        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpHeadsetDevice, false);
+        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpHeadsetDevice);
         verify(mHeadsetService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpHeadsetDevice);
 
         leAudioActiveDeviceChanged(mLeAudioDevice);
-        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(null, true);
+        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(isNull());
         verify(mHeadsetService, timeout(TIMEOUT_MS)).setActiveDevice(isNull());
     }
 
@@ -519,7 +483,7 @@
         headsetConnected(mA2dpHeadsetDevice);
 
         TestUtils.waitForLooperToFinishScheduledTask(mActiveDeviceManager.getHandlerLooper());
-        verify(mA2dpService).setActiveDevice(mA2dpHeadsetDevice, false);
+        verify(mA2dpService).setActiveDevice(mA2dpHeadsetDevice);
         verify(mHeadsetService).setActiveDevice(mA2dpHeadsetDevice);
     }
 
@@ -536,8 +500,8 @@
         a2dpActiveDeviceChanged(mA2dpHeadsetDevice);
 
         TestUtils.waitForLooperToFinishScheduledTask(mActiveDeviceManager.getHandlerLooper());
-        verify(mLeAudioService).setActiveDevice(null, true);
-        verify(mA2dpService).setActiveDevice(mA2dpHeadsetDevice, false);
+        verify(mLeAudioService).setActiveDevice(isNull());
+        verify(mA2dpService).setActiveDevice(mA2dpHeadsetDevice);
         Assert.assertEquals(mA2dpHeadsetDevice, mActiveDeviceManager.getA2dpActiveDevice());
         Assert.assertEquals(null, mActiveDeviceManager.getLeAudioActiveDevice());
     }
@@ -549,13 +513,13 @@
     public void leAudioActive_setHeadsetActiveExplicitly() {
         Assume.assumeTrue("Ignore test when LeAudioService is not enabled",
                 LeAudioService.isEnabled());
-        when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_IN_CALL);
+
         leAudioActiveDeviceChanged(mLeAudioDevice);
         headsetConnected(mA2dpHeadsetDevice);
         headsetActiveDeviceChanged(mA2dpHeadsetDevice);
 
         TestUtils.waitForLooperToFinishScheduledTask(mActiveDeviceManager.getHandlerLooper());
-        verify(mLeAudioService).setActiveDevice(null, false);
+        verify(mLeAudioService).setActiveDevice(isNull());
         verify(mHeadsetService).setActiveDevice(mA2dpHeadsetDevice);
         Assert.assertEquals(mA2dpHeadsetDevice, mActiveDeviceManager.getHfpActiveDevice());
         Assert.assertEquals(null, mActiveDeviceManager.getLeAudioActiveDevice());
@@ -570,15 +534,15 @@
         when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_NORMAL);
 
         leAudioConnected(mLeAudioDevice);
-        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(mLeAudioDevice, false);
+        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(mLeAudioDevice);
 
         a2dpConnected(mA2dpDevice);
-        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpDevice, false);
+        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpDevice);
 
         Mockito.clearInvocations(mLeAudioService);
         a2dpDisconnected(mA2dpDevice);
-        verify(mA2dpService, timeout(TIMEOUT_MS).atLeast(1)).setActiveDevice(null, true);
-        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(mLeAudioDevice, false);
+        verify(mA2dpService, timeout(TIMEOUT_MS).atLeast(1)).setActiveDevice(isNull());
+        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(mLeAudioDevice);
     }
 
     /**
@@ -590,15 +554,15 @@
         when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_NORMAL);
 
         a2dpConnected(mA2dpDevice);
-        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpDevice, false);
+        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpDevice);
 
         leAudioConnected(mLeAudioDevice);
-        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(mLeAudioDevice, false);
+        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(mLeAudioDevice);
 
         Mockito.clearInvocations(mA2dpService);
         leAudioDisconnected(mLeAudioDevice);
-        verify(mLeAudioService, timeout(TIMEOUT_MS).atLeast(1)).setActiveDevice(null, true);
-        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpDevice, false);
+        verify(mLeAudioService, timeout(TIMEOUT_MS).atLeast(1)).setActiveDevice(isNull());
+        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpDevice);
     }
 
     /**
@@ -608,15 +572,14 @@
     @Test
     public void hearingAidSecondDeviceDisconnected_fallbackDeviceActive() {
         hearingAidConnected(mHearingAidDevice);
-        verify(mHearingAidService, timeout(TIMEOUT_MS)).setActiveDevice(mHearingAidDevice, false);
+        verify(mHearingAidService, timeout(TIMEOUT_MS)).setActiveDevice(mHearingAidDevice);
 
         hearingAidConnected(mSecondaryAudioDevice);
-        verify(mHearingAidService, timeout(TIMEOUT_MS))
-                .setActiveDevice(mSecondaryAudioDevice, false);
+        verify(mHearingAidService, timeout(TIMEOUT_MS)).setActiveDevice(mSecondaryAudioDevice);
 
         Mockito.clearInvocations(mHearingAidService);
         hearingAidDisconnected(mSecondaryAudioDevice);
-        verify(mHearingAidService, timeout(TIMEOUT_MS)).setActiveDevice(mHearingAidDevice, false);
+        verify(mHearingAidService, timeout(TIMEOUT_MS)).setActiveDevice(mHearingAidDevice);
     }
 
     /**
@@ -628,7 +591,7 @@
         when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_NORMAL);
 
         hearingAidConnected(mHearingAidDevice);
-        verify(mHearingAidService, timeout(TIMEOUT_MS)).setActiveDevice(mHearingAidDevice, false);
+        verify(mHearingAidService, timeout(TIMEOUT_MS)).setActiveDevice(mHearingAidDevice);
 
         leAudioConnected(mLeAudioDevice);
         a2dpConnected(mA2dpDevice);
@@ -636,14 +599,14 @@
         a2dpActiveDeviceChanged(mA2dpDevice);
         TestUtils.waitForLooperToFinishScheduledTask(mActiveDeviceManager.getHandlerLooper());
 
-        verify(mHearingAidService).setActiveDevice(null, true);
+        verify(mHearingAidService).setActiveDevice(isNull());
         verify(mLeAudioService, never()).setActiveDevice(mLeAudioDevice);
-        verify(mA2dpService, never()).setActiveDevice(mA2dpDevice, false);
+        verify(mA2dpService, never()).setActiveDevice(mA2dpDevice);
 
         a2dpDisconnected(mA2dpDevice);
-        verify(mA2dpService, timeout(TIMEOUT_MS).atLeast(1)).setActiveDevice(null, true);
+        verify(mA2dpService, timeout(TIMEOUT_MS).atLeast(1)).setActiveDevice(isNull());
         verify(mHearingAidService, timeout(TIMEOUT_MS).times(2))
-                .setActiveDevice(mHearingAidDevice, false);
+                .setActiveDevice(mHearingAidDevice);
     }
 
     /**
@@ -656,7 +619,7 @@
         verify(mLeAudioService, never()).setActiveDevice(mLeHearingAidDevice);
 
         leAudioConnected(mLeHearingAidDevice);
-        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(mLeHearingAidDevice, false);
+        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(mLeHearingAidDevice);
     }
 
     /**
@@ -667,7 +630,7 @@
     public void leAudioConnectedAfterLeHearingAid_setLeAudioActiveShouldNotBeCalled() {
         leHearingAidConnected(mLeHearingAidDevice);
         leAudioConnected(mLeHearingAidDevice);
-        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(mLeHearingAidDevice, false);
+        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(mLeHearingAidDevice);
 
         leAudioConnected(mLeAudioDevice);
         TestUtils.waitForLooperToFinishScheduledTask(mActiveDeviceManager.getHandlerLooper());
@@ -684,24 +647,24 @@
         when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_NORMAL);
 
         hearingAidConnected(mHearingAidDevice);
-        verify(mHearingAidService, timeout(TIMEOUT_MS)).setActiveDevice(mHearingAidDevice, false);
+        verify(mHearingAidService, timeout(TIMEOUT_MS)).setActiveDevice(mHearingAidDevice);
 
         leHearingAidConnected(mLeHearingAidDevice);
         leAudioConnected(mLeHearingAidDevice);
-        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(mLeHearingAidDevice, false);
+        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(mLeHearingAidDevice);
 
         a2dpConnected(mA2dpDevice);
         TestUtils.waitForLooperToFinishScheduledTask(mActiveDeviceManager.getHandlerLooper());
-        verify(mA2dpService, never()).setActiveDevice(mA2dpDevice, false);
+        verify(mA2dpService, never()).setActiveDevice(mA2dpDevice);
 
         Mockito.clearInvocations(mHearingAidService, mA2dpService);
         leHearingAidDisconnected(mLeHearingAidDevice);
         leAudioDisconnected(mLeHearingAidDevice);
-        verify(mHearingAidService, timeout(TIMEOUT_MS)).setActiveDevice(mHearingAidDevice, false);
-        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(null, true);
+        verify(mHearingAidService, timeout(TIMEOUT_MS)).setActiveDevice(mHearingAidDevice);
+        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(isNull());
 
         hearingAidDisconnected(mHearingAidDevice);
-        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpDevice, false);
+        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpDevice);
     }
 
     /**
@@ -711,57 +674,13 @@
     public void wiredAudioDeviceConnected_setAllActiveDevicesNull() {
         a2dpConnected(mA2dpDevice);
         headsetConnected(mHeadsetDevice);
-        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpDevice, false);
+        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpDevice);
         verify(mHeadsetService, timeout(TIMEOUT_MS)).setActiveDevice(mHeadsetDevice);
 
         mActiveDeviceManager.wiredAudioDeviceConnected();
-        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(null, false);
+        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(isNull());
         verify(mHeadsetService, timeout(TIMEOUT_MS)).setActiveDevice(isNull());
-        verify(mHearingAidService, timeout(TIMEOUT_MS)).setActiveDevice(null, false);
-    }
-
-    @Test
-    public void leAudioActive_whileMediaPlayback_useLeAudioForMediaAndHeadsetForCall() {
-        leAudioConnected(mLeAudioDevice);
-        a2dpConnected(mA2dpDevice);
-        headsetConnected(mHeadsetDevice);
-        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(mLeAudioDevice, false);
-        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpDevice, false);
-        verify(mHeadsetService, timeout(TIMEOUT_MS)).setActiveDevice(mHeadsetDevice);
-
-        Mockito.clearInvocations(mLeAudioService, mA2dpService, mHeadsetService);
-        leAudioActiveDeviceChanged(mLeAudioDevice);
-        TestUtils.waitForLooperToFinishScheduledTask(mActiveDeviceManager.getHandlerLooper());
-        verify(mA2dpService).setActiveDevice(null, true);
-        verify(mHeadsetService).setActiveDevice(null);
-
-        Mockito.clearInvocations(mLeAudioService, mA2dpService, mHeadsetService);
-        mAudioModeChangedListener.onModeChanged(AudioManager.MODE_IN_CALL);
-        verify(mHeadsetService).setActiveDevice(mHeadsetDevice);
-        verify(mLeAudioService).setActiveDevice(null, true);
-    }
-
-    @Test
-    public void leAudioActive_whileInCall_useLeAudioForCallAndHeadsetForMedia() {
-        when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_IN_CALL);
-
-        leAudioConnected(mLeAudioDevice);
-        headsetConnected(mHeadsetDevice);
-        a2dpConnected(mA2dpDevice);
-        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(mLeAudioDevice, false);
-        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpDevice, false);
-        verify(mHeadsetService, timeout(TIMEOUT_MS)).setActiveDevice(mHeadsetDevice);
-
-        Mockito.clearInvocations(mLeAudioService, mA2dpService, mHeadsetService);
-        leAudioActiveDeviceChanged(mLeAudioDevice);
-        TestUtils.waitForLooperToFinishScheduledTask(mActiveDeviceManager.getHandlerLooper());
-        verify(mA2dpService).setActiveDevice(null, true);
-        verify(mHeadsetService).setActiveDevice(null);
-
-        Mockito.clearInvocations(mLeAudioService, mA2dpService, mHeadsetService);
-        mAudioModeChangedListener.onModeChanged(AudioManager.MODE_NORMAL);
-        verify(mA2dpService).setActiveDevice(mA2dpDevice, false);
-        verify(mLeAudioService).setActiveDevice(null, true);
+        verify(mHearingAidService, timeout(TIMEOUT_MS)).setActiveDevice(isNull());
     }
 
     /**
diff --git a/android/app/tests/unit/src/com/android/bluetooth/hearingaid/HearingAidServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/hearingaid/HearingAidServiceTest.java
index 44d0c8d..cf74dfd 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/hearingaid/HearingAidServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/hearingaid/HearingAidServiceTest.java
@@ -183,10 +183,6 @@
         if (newState == BluetoothProfile.STATE_CONNECTED) {
             // ActiveDeviceManager calls setActiveDevice when connected.
             mService.setActiveDevice(device);
-        } else if (newState == BluetoothProfile.STATE_DISCONNECTED
-                && mService.getConnectedDevices().isEmpty()) {
-            // ActiveDeviceManager calls setActiveDevice(null) when all devices are disconnected.
-            mService.setActiveDevice(null);
         }
 
     }
diff --git a/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java
index 8f14e37..fcb6779 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java
@@ -32,7 +32,6 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.annotation.NonNull;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothLeAudio;
@@ -48,6 +47,7 @@
 import android.content.IntentFilter;
 import android.media.AudioManager;
 import android.media.BluetoothProfileConnectionInfo;
+import android.os.Parcel;
 import android.os.ParcelUuid;
 
 import androidx.test.InstrumentationRegistry;
@@ -55,12 +55,14 @@
 import androidx.test.rule.ServiceTestRule;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.bluetooth.R;
 import com.android.bluetooth.TestUtils;
 import com.android.bluetooth.btservice.AdapterService;
 import com.android.bluetooth.btservice.storage.DatabaseManager;
 import com.android.bluetooth.vc.VolumeControlService;
 
 import org.junit.After;
+import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -281,24 +283,15 @@
         }
     }
 
-    private void verifyConnectionStateIntent(int timeoutMs, @NonNull BluetoothDevice device,
+    private void verifyConnectionStateIntent(int timeoutMs, BluetoothDevice device,
             int newState, int prevState) {
         Intent intent = TestUtils.waitForIntent(timeoutMs, mDeviceQueueMap.get(device));
         assertThat(intent).isNotNull();
         assertThat(intent.getAction())
                 .isEqualTo(BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED);
         assertThat((BluetoothDevice)intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)).isEqualTo(device);
-        int newConnectionState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
-        assertThat(newConnectionState).isEqualTo(newState);
+        assertThat(intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1)).isEqualTo(newState);
         assertThat(intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, -1)).isEqualTo(prevState);
-
-        if (newConnectionState == BluetoothProfile.STATE_CONNECTED) {
-            // ActiveDeviceManager calls deviceConnected when connected.
-            mService.deviceConnected(device);
-        } else if (newConnectionState == BluetoothProfile.STATE_DISCONNECTED) {
-            // ActiveDeviceManager calls deviceDisconnected when connected.
-            mService.deviceDisconnected(device, false);
-        }
     }
 
     /**
@@ -1353,6 +1346,7 @@
 
         verify(mAudioManager, times(1)).handleBluetoothActiveDeviceChanged(any(), eq(leadDevice),
                 any(BluetoothProfileConnectionInfo.class));
+
     }
 
     /**
diff --git a/system/bta/Android.bp b/system/bta/Android.bp
index 62620a0..c33a732 100644
--- a/system/bta/Android.bp
+++ b/system/bta/Android.bp
@@ -606,6 +606,7 @@
         "le_audio/metrics_collector_linux.cc",
         "le_audio/mock_iso_manager.cc",
         "test/common/mock_controller.cc",
+        "test/common/mock_csis_client.cc",
         "le_audio/state_machine.cc",
         "le_audio/state_machine_test.cc",
         "le_audio/storage_helper.cc",
diff --git a/system/bta/csis/csis_client.cc b/system/bta/csis/csis_client.cc
index a210dc4..4ef353f 100644
--- a/system/bta/csis/csis_client.cc
+++ b/system/bta/csis/csis_client.cc
@@ -525,6 +525,16 @@
     }
   }
 
+  int GetDesiredSize(int group_id) override {
+    auto csis_group = FindCsisGroup(group_id);
+    if (!csis_group) {
+      LOG_INFO("Unknown group %d", group_id);
+      return -1;
+    }
+
+    return csis_group->GetDesiredSize();
+  }
+
   bool SerializeSets(const RawAddress& addr, std::vector<uint8_t>& out) const {
     auto device = FindDeviceByAddress(addr);
     if (device == nullptr) {
diff --git a/system/bta/csis/csis_types.h b/system/bta/csis/csis_types.h
index 466a1d4..75783a4 100644
--- a/system/bta/csis/csis_types.h
+++ b/system/bta/csis/csis_types.h
@@ -64,7 +64,7 @@
 
 /* CSIS Types */
 static constexpr uint8_t kDefaultScanDurationS = 5;
-static constexpr uint8_t kDefaultCsisSetSize = 2;
+static constexpr uint8_t kDefaultCsisSetSize = 1;
 static constexpr uint8_t kUnknownRank = 0xff;
 
 /* Enums */
diff --git a/system/bta/include/bta_csis_api.h b/system/bta/include/bta_csis_api.h
index fe864f5..44dca04 100644
--- a/system/bta/include/bta_csis_api.h
+++ b/system/bta/include/bta_csis_api.h
@@ -47,6 +47,7 @@
       bluetooth::Uuid uuid = bluetooth::groups::kGenericContextUuid) = 0;
   virtual void LockGroup(int group_id, bool lock, CsisLockCb cb) = 0;
   virtual std::vector<RawAddress> GetDeviceList(int group_id) = 0;
+  virtual int GetDesiredSize(int group_id) = 0;
 };
 }  // namespace csis
 }  // namespace bluetooth
diff --git a/system/bta/le_audio/devices.cc b/system/bta/le_audio/devices.cc
index debd733..50944c2 100644
--- a/system/bta/le_audio/devices.cc
+++ b/system/bta/le_audio/devices.cc
@@ -22,6 +22,7 @@
 #include <map>
 
 #include "audio_hal_client/audio_hal_client.h"
+#include "bta_csis_api.h"
 #include "bta_gatt_queue.h"
 #include "bta_groups.h"
 #include "bta_le_audio_api.h"
@@ -967,10 +968,16 @@
   uint8_t cis_count_bidir = 0;
   uint8_t cis_count_unidir_sink = 0;
   uint8_t cis_count_unidir_source = 0;
-  get_cis_count(confs, GetGroupStrategy(),
+  int csis_group_size =
+      bluetooth::csis::CsisClient::Get()->GetDesiredSize(group_id_);
+  /* If this is CSIS group, the csis_group_size will be > 0, otherwise -1.
+   * If the last happen it means, group size is 1 */
+  int group_size = csis_group_size > 0 ? csis_group_size : 1;
+
+  get_cis_count(*confs, group_size, GetGroupStrategy(),
                 GetAseCount(types::kLeAudioDirectionSink),
-                GetAseCount(types::kLeAudioDirectionSource), &cis_count_bidir,
-                &cis_count_unidir_sink, &cis_count_unidir_source);
+                GetAseCount(types::kLeAudioDirectionSource), cis_count_bidir,
+                cis_count_unidir_sink, cis_count_unidir_source);
 
   uint8_t idx = 0;
   while (cis_count_bidir > 0) {
@@ -980,7 +987,6 @@
         .type = CisType::CIS_TYPE_BIDIRECTIONAL,
         .conn_handle = 0,
     };
-
     cises_.push_back(cis_entry);
     cis_count_bidir--;
     idx++;
@@ -1045,18 +1051,21 @@
         cis_id = GetFirstFreeCisId(CisType::CIS_TYPE_BIDIRECTIONAL);
       }
 
-      if (cis_id == kInvalidCisId) {
-        LOG_ERROR(" Unable to get free Bi-Directional CIS ID");
-        return false;
+      if (cis_id != kInvalidCisId) {
+        ase->cis_id = cis_id;
+        matching_bidir_ase->cis_id = cis_id;
+        cises_[cis_id].addr = leAudioDevice->address_;
+
+        LOG_INFO(
+            " ASE ID: %d and ASE ID: %d, assigned Bi-Directional CIS ID: %d",
+            +ase->id, +matching_bidir_ase->id, +ase->cis_id);
+        continue;
       }
 
-      ase->cis_id = cis_id;
-      matching_bidir_ase->cis_id = cis_id;
-      cises_[cis_id].addr = leAudioDevice->address_;
-
-      LOG_INFO(" ASE ID: %d and ASE ID: %d, assigned Bi-Directional CIS ID: %d",
-               +ase->id, +matching_bidir_ase->id, +ase->cis_id);
-      continue;
+      LOG_WARN(
+          " ASE ID: %d, unable to get free Bi-Directional CIS ID but maybe "
+          "thats fine. Try using unidirectional.",
+          ase->id);
     }
 
     if (ase->direction == types::kLeAudioDirectionSink) {
@@ -1267,7 +1276,7 @@
 
     if (ent.direction == types::kLeAudioDirectionSink &&
         strategy != required_snk_strategy) {
-      LOG_INFO(" Sink strategy mismatch (%d!=%d)",
+      LOG_INFO(" Sink strategy mismatch group!=cfg.entry (%d!=%d)",
                static_cast<int>(required_snk_strategy),
                static_cast<int>(strategy));
       return false;
@@ -1545,12 +1554,12 @@
                       std::vector<uint8_t>());
     }
 
-    DLOG(INFO) << __func__ << " device=" << address_
-               << ", activated ASE id=" << +ase->id
-               << ", direction=" << +ase->direction
-               << ", max_sdu_size=" << +ase->max_sdu_size
-               << ", cis_id=" << +ase->cis_id
-               << ", target_latency=" << +ent.target_latency;
+    LOG_DEBUG(
+        "device=%s, activated ASE id=%d, direction=%s, max_sdu_size=%d, "
+        "cis_id=%d, target_latency=%d",
+        address_.ToString().c_str(), ase->id,
+        (ent.direction == 1 ? "snk" : "src"), ase->max_sdu_size, ase->cis_id,
+        ent.target_latency);
 
     /* Try to use the already active ASE */
     ase = GetNextActiveAseWithSameDirection(ase);
@@ -1589,9 +1598,9 @@
   types::AudioLocations group_src_audio_locations = 0;
 
   for (const auto& ent : (*audio_set_conf).confs) {
-    DLOG(INFO) << __func__
-               << " Looking for requirements: " << audio_set_conf->name << " - "
-               << (ent.direction == 1 ? "snk" : "src");
+    LOG_DEBUG(" Looking for requirements: %s,  - %s",
+              audio_set_conf->name.c_str(),
+              (ent.direction == 1 ? "snk" : "src"));
 
     uint8_t required_device_cnt = ent.device_cnt;
     uint8_t max_required_ase_per_dev =
@@ -1599,10 +1608,11 @@
     uint8_t active_ase_num = 0;
     le_audio::types::LeAudioConfigurationStrategy strategy = ent.strategy;
 
-    DLOG(INFO) << __func__ << " Number of devices: " << +required_device_cnt
-               << " number of ASEs: " << +ent.ase_cnt
-               << " Max ASE per device: " << +max_required_ase_per_dev
-               << " strategy: " << (int)strategy;
+    LOG_DEBUG(
+        "Number of devices: %d number of ASEs: %d, Max ASE per device: %d "
+        "strategy: %d",
+        required_device_cnt, ent.ase_cnt, max_required_ase_per_dev,
+        (int)strategy);
 
     for (auto* device = GetFirstDeviceWithActiveContext(context_type);
          device != nullptr && required_device_cnt > 0;
@@ -1629,14 +1639,14 @@
 
     if (required_device_cnt > 0) {
       /* Don't left any active devices if requirements are not met */
-      LOG(ERROR) << __func__ << " could not configure all the devices";
+      LOG_ERROR(" could not configure all the devices");
       Deactivate();
       return false;
     }
   }
 
-  LOG(INFO) << "Choosed ASE Configuration for group: " << this->group_id_
-            << " configuration: " << audio_set_conf->name;
+  LOG_INFO("Choosed ASE Configuration for group: %d, configuration: %s",
+           group_id_, audio_set_conf->name.c_str());
 
   configuration_context_type_ = context_type;
   metadata_context_type_ = metadata_context_type;
@@ -1912,21 +1922,22 @@
   const set_configurations::AudioSetConfiguration* conf =
       available_context_to_configuration_map[context_type];
 
-  DLOG(INFO) << __func__;
-
   if (!conf) {
-    LOG(ERROR) << __func__ << ", requested context type: "
-               << loghex(static_cast<uint16_t>(context_type))
-               << ", is in mismatch with cached available contexts";
+    LOG_ERROR(
+        ", requested context type: %s , is in mismatch with cached available "
+        "contexts ",
+        bluetooth::common::ToString(context_type).c_str());
     return false;
   }
 
-  DLOG(INFO) << __func__ << " setting context type: " << int(context_type);
+  LOG_DEBUG(" setting context type: %s",
+            bluetooth::common::ToString(context_type).c_str());
 
   if (!ConfigureAses(conf, context_type, metadata_context_type, ccid_list)) {
-    LOG(ERROR) << __func__ << ", requested pick ASE config context type: "
-               << loghex(static_cast<uint16_t>(context_type))
-               << ", is in mismatch with cached available contexts";
+    LOG_ERROR(
+        ", requested context type: %s , is in mismatch with cached available "
+        "contexts",
+        bluetooth::common::ToString(context_type).c_str());
     return false;
   }
 
diff --git a/system/bta/le_audio/devices_test.cc b/system/bta/le_audio/devices_test.cc
index 8dbedf6..a7a3cda 100644
--- a/system/bta/le_audio/devices_test.cc
+++ b/system/bta/le_audio/devices_test.cc
@@ -24,6 +24,8 @@
 #include "le_audio_set_configuration_provider.h"
 #include "le_audio_types.h"
 #include "mock_controller.h"
+#include "mock_csis_client.h"
+#include "os/log.h"
 #include "stack/btm/btm_int_types.h"
 
 tACL_CONN* btm_bda_to_acl(const RawAddress& bda, tBT_TRANSPORT transport) {
@@ -42,6 +44,9 @@
 using ::le_audio::types::AseState;
 using ::le_audio::types::AudioContexts;
 using ::le_audio::types::LeAudioContextType;
+using testing::_;
+using testing::Invoke;
+using testing::Return;
 using testing::Test;
 
 RawAddress GetTestAddress(int index) {
@@ -399,12 +404,23 @@
     bluetooth::manager::SetMockBtmInterface(&btm_interface_);
     controller::SetMockControllerInterface(&controller_interface_);
     ::le_audio::AudioSetConfigurationProvider::Initialize();
+    MockCsisClient::SetMockInstanceForTesting(&mock_csis_client_module_);
+    ON_CALL(mock_csis_client_module_, Get())
+        .WillByDefault(Return(&mock_csis_client_module_));
+    ON_CALL(mock_csis_client_module_, IsCsisClientRunning())
+        .WillByDefault(Return(true));
+    ON_CALL(mock_csis_client_module_, GetDeviceList(_))
+        .WillByDefault(Invoke([this](int group_id) { return addresses_; }));
+    ON_CALL(mock_csis_client_module_, GetDesiredSize(_))
+        .WillByDefault(
+            Invoke([this](int group_id) { return (int)(addresses_.size()); }));
   }
 
   void TearDown() override {
     controller::SetMockControllerInterface(nullptr);
     bluetooth::manager::SetMockBtmInterface(nullptr);
     devices_.clear();
+    addresses_.clear();
     delete group_;
     ::le_audio::AudioSetConfigurationProvider::Cleanup();
   }
@@ -416,6 +432,10 @@
     auto device = (std::make_shared<LeAudioDevice>(
         GetTestAddress(index), DeviceConnectState::DISCONNECTED));
     devices_.push_back(device);
+    LOG_INFO(" addresses %d", (int)(addresses_.size()));
+    addresses_.push_back(device->address_);
+    LOG_INFO(" Addresses %d", (int)(addresses_.size()));
+
     group_->AddNode(device);
 
     int ase_id = 1;
@@ -760,9 +780,11 @@
 
   const int group_id_ = 6;
   std::vector<std::shared_ptr<LeAudioDevice>> devices_;
+  std::vector<RawAddress> addresses_;
   LeAudioDeviceGroup* group_ = nullptr;
   bluetooth::manager::MockBtmInterface btm_interface_;
   controller::MockControllerInterface controller_interface_;
+  MockCsisClient mock_csis_client_module_;
 };
 
 TEST_F(LeAudioAseConfigurationTest, test_mono_speaker_ringtone) {
diff --git a/system/bta/le_audio/le_audio_client_test.cc b/system/bta/le_audio/le_audio_client_test.cc
index 8d8d1c4..5acdeed 100644
--- a/system/bta/le_audio/le_audio_client_test.cc
+++ b/system/bta/le_audio/le_audio_client_test.cc
@@ -3358,6 +3358,9 @@
                     codec_spec_conf::kLeAudioLocationFrontRight, group_size,
                     group_id, 2 /* rank*/, true /*connect_through_csis*/);
 
+  ON_CALL(mock_csis_client_module_, GetDesiredSize(group_id))
+      .WillByDefault(Invoke([&](int group_id) { return 2; }));
+
   // Start streaming
   EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _)).Times(1);
   EXPECT_CALL(*mock_le_audio_sink_hal_client_, Start(_, _)).Times(1);
@@ -3428,6 +3431,9 @@
                     codec_spec_conf::kLeAudioLocationFrontRight, group_size,
                     group_id, 2 /* rank*/, true /*connect_through_csis*/);
 
+  ON_CALL(mock_csis_client_module_, GetDesiredSize(group_id))
+      .WillByDefault(Invoke([&](int group_id) { return 2; }));
+
   // Start streaming
   EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _)).Times(1);
   EXPECT_CALL(*mock_le_audio_sink_hal_client_, Start(_, _)).Times(1);
@@ -3526,6 +3532,9 @@
   constexpr int gmcs_ccid = 1;
   constexpr int gtbs_ccid = 2;
 
+  ON_CALL(mock_csis_client_module_, GetDesiredSize(group_id))
+      .WillByDefault(Invoke([&](int group_id) { return 2; }));
+
   // Start streaming MEDIA
   EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _)).Times(1);
   EXPECT_CALL(*mock_le_audio_sink_hal_client_, Start(_, _)).Times(1);
@@ -3575,8 +3584,10 @@
   ON_CALL(mock_csis_client_module_, IsCsisClientRunning())
       .WillByDefault(Return(true));
 
-  // First earbud
   const RawAddress test_address0 = GetTestAddress(0);
+  const RawAddress test_address1 = GetTestAddress(1);
+
+  // First earbud
   ConnectCsisDevice(test_address0, 1 /*conn_id*/,
                     codec_spec_conf::kLeAudioLocationFrontLeft,
                     codec_spec_conf::kLeAudioLocationFrontLeft, group_size,
@@ -3587,6 +3598,9 @@
   EXPECT_CALL(*mock_le_audio_sink_hal_client_, Start(_, _)).Times(1);
   LeAudioClient::Get()->GroupSetActive(group_id);
 
+  ON_CALL(mock_csis_client_module_, GetDesiredSize(group_id))
+      .WillByDefault(Invoke([&](int group_id) { return 2; }));
+
   StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id);
 
   Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_);
@@ -3599,7 +3613,6 @@
   TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920);
 
   // Second earbud connects during stream
-  const RawAddress test_address1 = GetTestAddress(1);
   ConnectCsisDevice(test_address1, 2 /*conn_id*/,
                     codec_spec_conf::kLeAudioLocationFrontRight,
                     codec_spec_conf::kLeAudioLocationFrontRight, group_size,
@@ -3637,6 +3650,9 @@
                     codec_spec_conf::kLeAudioLocationFrontRight, group_size,
                     group_id, 2 /* rank*/, true /*connect_through_csis*/);
 
+  ON_CALL(mock_csis_client_module_, GetDesiredSize(group_id))
+      .WillByDefault(Invoke([&](int group_id) { return 2; }));
+
   // Audio sessions are started only when device gets active
   EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _)).Times(1);
   EXPECT_CALL(*mock_le_audio_sink_hal_client_, Start(_, _)).Times(1);
@@ -3705,6 +3721,9 @@
                     codec_spec_conf::kLeAudioLocationFrontRight, group_size,
                     group_id, 2 /* rank*/, true /*connect_through_csis*/);
 
+  ON_CALL(mock_csis_client_module_, GetDesiredSize(group_id))
+      .WillByDefault(Invoke([&](int group_id) { return 2; }));
+
   // Audio sessions are started only when device gets active
   EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _)).Times(1);
   EXPECT_CALL(*mock_le_audio_sink_hal_client_, Start(_, _)).Times(1);
diff --git a/system/bta/le_audio/le_audio_types.cc b/system/bta/le_audio/le_audio_types.cc
index c0d6ed5..29d69ec 100644
--- a/system/bta/le_audio/le_audio_types.cc
+++ b/system/bta/le_audio/le_audio_types.cc
@@ -70,124 +70,154 @@
   return curr_min_req_devices_cnt;
 }
 
-void get_cis_count(const AudioSetConfigurations* audio_set_confs,
-                   types::LeAudioConfigurationStrategy strategy,
-                   int group_ase_snk_cnt, int group_ase_src_count,
-                   uint8_t* cis_count_bidir, uint8_t* cis_count_unidir_sink,
-                   uint8_t* cis_count_unidir_source) {
-  LOG_INFO(" strategy %d, sink ases: %d, source ases %d",
-           static_cast<int>(strategy), group_ase_snk_cnt, group_ase_src_count);
+inline void get_cis_count(const AudioSetConfiguration& audio_set_conf,
+                          int expected_device_cnt,
+                          types::LeAudioConfigurationStrategy strategy,
+                          int avail_group_sink_ase_count,
+                          int avail_group_source_ase_count,
+                          uint8_t& out_current_cis_count_bidir,
+                          uint8_t& out_current_cis_count_unidir_sink,
+                          uint8_t& out_current_cis_count_unidir_source) {
+  LOG_INFO("%s", audio_set_conf.name.c_str());
 
-  for (auto audio_set_conf : *audio_set_confs) {
-    std::pair<uint8_t /* sink */, uint8_t /* source */> snk_src_pair(0, 0);
-    uint8_t bidir_count = 0;
-    uint8_t unidir_sink_count = 0;
-    uint8_t unidir_source_count = 0;
+  /* Sum up the requirements from all subconfigs. They usually have different
+   * directions.
+   */
+  types::BidirectionalPair<uint8_t> config_ase_count = {0, 0};
+  int config_device_cnt = 0;
 
-    LOG_INFO("%s ", audio_set_conf->name.c_str());
-    bool stategy_mismatch = false;
-    for (auto ent : (*audio_set_conf).confs) {
-      if (ent.strategy != strategy) {
-        LOG_DEBUG("Strategy does not match (%d != %d)- skip this configuration",
-                  static_cast<int>(ent.strategy), static_cast<int>(strategy));
-        stategy_mismatch = true;
-        break;
-      }
-      if (ent.direction == kLeAudioDirectionSink) {
-        snk_src_pair.first += ent.ase_cnt;
-      }
-      if (ent.direction == kLeAudioDirectionSource) {
-        snk_src_pair.second += ent.ase_cnt;
-      }
+  for (auto ent : audio_set_conf.confs) {
+    if ((ent.direction == kLeAudioDirectionSink) &&
+        (ent.strategy != strategy)) {
+      LOG_DEBUG("Strategy does not match (%d != %d)- skip this configuration",
+                static_cast<int>(ent.strategy), static_cast<int>(strategy));
+      return;
     }
 
-    if (stategy_mismatch) {
-      continue;
+    /* Sum up sink and source ases */
+    if (ent.direction == kLeAudioDirectionSink) {
+      config_ase_count.sink += ent.ase_cnt;
+    }
+    if (ent.direction == kLeAudioDirectionSource) {
+      config_ase_count.source += ent.ase_cnt;
     }
 
-    /* Before we start adding another CISes, ignore scenarios which cannot
-     * satisfied because of the number of ases
-     */
+    /* Calculate the max device count */
+    config_device_cnt =
+        std::max(static_cast<uint8_t>(config_device_cnt), ent.device_cnt);
+  }
 
-    if (group_ase_snk_cnt == 0 && snk_src_pair.first > 0) {
-      LOG_DEBUG("Group does not have sink ASEs");
-      continue;
+  LOG_DEBUG("Config sink ases: %d, source ases: %d, device count: %d",
+            config_ase_count.sink, config_ase_count.source, config_device_cnt);
+
+  /* Reject configurations not matching our device count */
+  if (expected_device_cnt != config_device_cnt) {
+    LOG_DEBUG(" Device cnt %d != %d", expected_device_cnt, config_device_cnt);
+    return;
+  }
+
+  /* Reject configurations requiring sink ASES if our group has none */
+  if ((avail_group_sink_ase_count == 0) && (config_ase_count.sink > 0)) {
+    LOG_DEBUG("Group does not have sink ASEs");
+    return;
+  }
+
+  /* Reject configurations requiring source ASES if our group has none */
+  if ((avail_group_source_ase_count == 0) && (config_ase_count.source > 0)) {
+    LOG_DEBUG("Group does not have source ASEs");
+    return;
+  }
+
+  /* If expected group size is 1, then make sure device has enough ASEs */
+  if (expected_device_cnt == 1) {
+    if ((config_ase_count.sink > avail_group_sink_ase_count) ||
+        (config_ase_count.source > avail_group_source_ase_count)) {
+      LOG_DEBUG("Single device group with not enought sink/source ASEs");
+      return;
     }
+  }
 
-    if (group_ase_src_count == 0 && snk_src_pair.second > 0) {
-      LOG_DEBUG("Group does not have source ASEs");
-      continue;
-    }
-
-    /* Configuration list is set in the prioritized order.
-     * it might happen that more prio configuration can be supported
-     * and is already taken into account.
-     * Now let's try to ignore ortogonal configuration which would just
-     * increase our demant on number of CISes but will never happen
-     */
-
-    if (snk_src_pair.first == 0 &&
-        (*cis_count_unidir_sink > 0 || *cis_count_bidir > 0)) {
-      LOG_DEBUG(
-          "More prio configuration using sink ASEs has been taken into "
-          "account");
-      continue;
-    }
-    if (snk_src_pair.second == 0 &&
-        (*cis_count_unidir_source > 0 || *cis_count_bidir > 0)) {
-      LOG_DEBUG(
-          "More prio configuration using source ASEs has been taken into "
-          "account");
-      continue;
-    }
-
-    bidir_count = std::min(snk_src_pair.first, snk_src_pair.second);
-    unidir_sink_count = ((snk_src_pair.first - bidir_count) > 0)
-                            ? (snk_src_pair.first - bidir_count)
-                            : 0;
-    unidir_source_count = ((snk_src_pair.second - bidir_count) > 0)
-                              ? (snk_src_pair.second - bidir_count)
-                              : 0;
-
-    *cis_count_bidir = std::max(bidir_count, *cis_count_bidir);
-
-    /* Check if we can reduce a number of unicast CISes in case bidirectional
-     * are use in other or this scenario */
-    if (bidir_count < *cis_count_bidir) {
-      /* Since we already have bidirectional cises available from other
-       * scenarios, let's decrease number of unicast sinks in this scenario.
-       */
-      uint8_t available_bidir = *cis_count_bidir - bidir_count;
-      unidir_sink_count =
-          unidir_sink_count - std::min(unidir_sink_count, available_bidir);
-      unidir_source_count =
-          unidir_source_count - std::min(unidir_source_count, available_bidir);
-    } else if (bidir_count > *cis_count_bidir) {
-      /* Lets decrease number of the unicast cises from previouse scenarios */
-      uint8_t available_bidir = bidir_count - *cis_count_bidir;
-      *cis_count_unidir_sink =
-          *cis_count_unidir_sink -
-          std::min(*cis_count_unidir_sink, available_bidir);
-      *cis_count_unidir_source =
-          *cis_count_unidir_source -
-          std::min(*cis_count_unidir_source, available_bidir);
-    }
-
-    *cis_count_unidir_sink =
-        std::max(unidir_sink_count, *cis_count_unidir_sink);
-    *cis_count_unidir_source =
-        std::max(unidir_source_count, *cis_count_unidir_source);
-
+  /* Configuration list is set in the prioritized order.
+   * it might happen that a higher prio configuration can be supported
+   * and is already taken into account (out_current_cis_count_* is non zero).
+   * Now let's try to ignore ortogonal configuration which would just
+   * increase our demant on number of CISes but will never happen
+   */
+  if (config_ase_count.sink == 0 && (out_current_cis_count_unidir_sink > 0 ||
+                                     out_current_cis_count_bidir > 0)) {
     LOG_INFO(
+        "Higher prio configuration using sink ASEs has been taken into "
+        "account");
+    return;
+  }
+
+  if (config_ase_count.source == 0 &&
+      (out_current_cis_count_unidir_source > 0 ||
+       out_current_cis_count_bidir > 0)) {
+    LOG_INFO(
+        "Higher prio configuration using source ASEs has been taken into "
+        "account");
+    return;
+  }
+
+  /* Check how many bidirectional cises we can use */
+  uint8_t config_bidir_cis_count =
+      std::min(config_ase_count.sink, config_ase_count.source);
+  /* Count the remaining unidirectional cises */
+  uint8_t config_unidir_sink_cis_count =
+      config_ase_count.sink - config_bidir_cis_count;
+  uint8_t config_unidir_source_cis_count =
+      config_ase_count.source - config_bidir_cis_count;
+
+  /* WARNING: Minipolicy which prioritizes bidirectional configs */
+  if (config_bidir_cis_count > out_current_cis_count_bidir) {
+    /* Correct all counters to represent this single config */
+    out_current_cis_count_bidir = config_bidir_cis_count;
+    out_current_cis_count_unidir_sink = config_unidir_sink_cis_count;
+    out_current_cis_count_unidir_source = config_unidir_source_cis_count;
+
+  } else if (out_current_cis_count_bidir == 0) {
+    /* No bidirectionals possible yet. Calculate for unidirectional cises. */
+    if ((out_current_cis_count_unidir_sink == 0) &&
+        (out_current_cis_count_unidir_source == 0)) {
+      out_current_cis_count_unidir_sink = config_unidir_sink_cis_count;
+      out_current_cis_count_unidir_source = config_unidir_source_cis_count;
+    }
+  }
+}
+
+void get_cis_count(const AudioSetConfigurations& audio_set_confs,
+                   int expected_device_cnt,
+                   types::LeAudioConfigurationStrategy strategy,
+                   int avail_group_ase_snk_cnt, int avail_group_ase_src_count,
+                   uint8_t& out_cis_count_bidir,
+                   uint8_t& out_cis_count_unidir_sink,
+                   uint8_t& out_cis_count_unidir_source) {
+  LOG_INFO(
+      " strategy %d, group avail sink ases: %d, group avail source ases %d "
+      "expected_device_count %d",
+      static_cast<int>(strategy), avail_group_ase_snk_cnt,
+      avail_group_ase_src_count, expected_device_cnt);
+
+  /* Look for the most optimal configuration and store the needed cis counts */
+  for (auto audio_set_conf : audio_set_confs) {
+    get_cis_count(*audio_set_conf, expected_device_cnt, strategy,
+                  avail_group_ase_snk_cnt, avail_group_ase_src_count,
+                  out_cis_count_bidir, out_cis_count_unidir_sink,
+                  out_cis_count_unidir_source);
+
+    LOG_DEBUG(
         "Intermediate step:  Bi-Directional: %d,"
         " Uni-Directional Sink: %d, Uni-Directional Source: %d ",
-        *cis_count_bidir, *cis_count_unidir_sink, *cis_count_unidir_source);
+        out_cis_count_bidir, out_cis_count_unidir_sink,
+        out_cis_count_unidir_source);
   }
 
   LOG_INFO(
       " Maximum CIS count, Bi-Directional: %d,"
       " Uni-Directional Sink: %d, Uni-Directional Source: %d",
-      *cis_count_bidir, *cis_count_unidir_sink, *cis_count_unidir_source);
+      out_cis_count_bidir, out_cis_count_unidir_sink,
+      out_cis_count_unidir_source);
 }
 
 bool check_if_may_cover_scenario(const AudioSetConfigurations* audio_set_confs,
diff --git a/system/bta/le_audio/le_audio_types.h b/system/bta/le_audio/le_audio_types.h
index 67dbeb4..b5935a5 100644
--- a/system/bta/le_audio/le_audio_types.h
+++ b/system/bta/le_audio/le_audio_types.h
@@ -751,11 +751,12 @@
     codec_spec_conf::kLeAudioLocationFrontRight;
 
 /* Declarations */
-void get_cis_count(const AudioSetConfigurations* audio_set_configurations,
+void get_cis_count(const AudioSetConfigurations& audio_set_configurations,
+                   int expected_device_cnt,
                    types::LeAudioConfigurationStrategy strategy,
                    int group_ase_snk_cnt, int group_ase_src_count,
-                   uint8_t* cis_count_bidir, uint8_t* cis_count_unidir_sink,
-                   uint8_t* cis_count_unidir_source);
+                   uint8_t& cis_count_bidir, uint8_t& cis_count_unidir_sink,
+                   uint8_t& cis_count_unidir_source);
 bool check_if_may_cover_scenario(
     const AudioSetConfigurations* audio_set_configurations, uint8_t group_size);
 bool check_if_may_cover_scenario(
diff --git a/system/bta/le_audio/state_machine.cc b/system/bta/le_audio/state_machine.cc
index 6384274..8476fec 100644
--- a/system/bta/le_audio/state_machine.cc
+++ b/system/bta/le_audio/state_machine.cc
@@ -214,7 +214,8 @@
 
       case AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING: {
         /* This case just updates the metadata for the stream, in case
-         * stream configuration is satisfied
+         * stream configuration is satisfied. We can do that already for
+         * all the devices in a group, without any state transitions.
          */
         if (!group->IsMetadataChanged(metadata_context_type, ccid_list))
           return true;
@@ -225,8 +226,11 @@
           return false;
         }
 
-        PrepareAndSendUpdateMetadata(group, leAudioDevice,
-                                     metadata_context_type, ccid_list);
+        while (leAudioDevice) {
+          PrepareAndSendUpdateMetadata(group, leAudioDevice,
+                                       metadata_context_type, ccid_list);
+          leAudioDevice = group->GetNextActiveDevice(leAudioDevice);
+        }
         break;
       }
 
diff --git a/system/bta/le_audio/state_machine_test.cc b/system/bta/le_audio/state_machine_test.cc
index da84810..2d0fc44 100644
--- a/system/bta/le_audio/state_machine_test.cc
+++ b/system/bta/le_audio/state_machine_test.cc
@@ -32,6 +32,7 @@
 #include "le_audio_set_configuration_provider.h"
 #include "mock_codec_manager.h"
 #include "mock_controller.h"
+#include "mock_csis_client.h"
 #include "mock_iso_manager.h"
 #include "types/bt_transport.h"
 
@@ -53,6 +54,10 @@
 extern struct fake_osi_alarm_set_on_mloop fake_osi_alarm_set_on_mloop_;
 
 void osi_property_set_bool(const char* key, bool value);
+static const char* test_flags[] = {
+    "INIT_logging_debug_enabled_for_all=true",
+    nullptr,
+};
 
 constexpr uint8_t media_ccid = 0xC0;
 constexpr auto media_context =
@@ -77,6 +82,8 @@
     static_cast<LeAudioContextType>(0x0002);
 constexpr LeAudioContextType kContextTypeMedia =
     static_cast<LeAudioContextType>(0x0004);
+constexpr LeAudioContextType kContextTypeSoundEffects =
+    static_cast<LeAudioContextType>(0x0080);
 constexpr LeAudioContextType kContextTypeRingtone =
     static_cast<LeAudioContextType>(0x0200);
 
@@ -146,11 +153,6 @@
   return {{0xC0, 0xDE, 0xC0, 0xDE, 0x00, index}};
 }
 
-static uint8_t ase_id_last_assigned;
-static uint8_t additional_ases = 0;
-static uint8_t channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel;
-static uint16_t sample_freq_ = codec_specific::kCapSamplingFrequency16000Hz;
-
 class MockLeAudioGroupStateMachineCallbacks
     : public LeAudioGroupStateMachine::Callbacks {
  public:
@@ -169,20 +171,36 @@
 
 class StateMachineTest : public Test {
  protected:
+  uint8_t ase_id_last_assigned = types::ase::kAseIdInvalid;
+  uint8_t additional_snk_ases = 0;
+  uint8_t additional_src_ases = 0;
+  uint8_t channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel;
+  uint16_t sample_freq_ = codec_specific::kCapSamplingFrequency16000Hz;
+
   void SetUp() override {
+    bluetooth::common::InitFlags::Load(test_flags);
     mock_function_count_map.clear();
     controller::SetMockControllerInterface(&mock_controller_);
     bluetooth::manager::SetMockBtmInterface(&btm_interface);
     gatt::SetMockBtaGattInterface(&gatt_interface);
     gatt::SetMockBtaGattQueue(&gatt_queue);
 
-    ase_id_last_assigned = types::ase::kAseIdInvalid;
-    additional_ases = 0;
     ::le_audio::AudioSetConfigurationProvider::Initialize();
     LeAudioGroupStateMachine::Initialize(&mock_callbacks_);
 
     ContentControlIdKeeper::GetInstance()->Start();
 
+    MockCsisClient::SetMockInstanceForTesting(&mock_csis_client_module_);
+    ON_CALL(mock_csis_client_module_, Get())
+        .WillByDefault(Return(&mock_csis_client_module_));
+    ON_CALL(mock_csis_client_module_, IsCsisClientRunning())
+        .WillByDefault(Return(true));
+    ON_CALL(mock_csis_client_module_, GetDeviceList(_))
+        .WillByDefault(Invoke([this](int group_id) { return addresses_; }));
+    ON_CALL(mock_csis_client_module_, GetDesiredSize(_))
+        .WillByDefault(
+            Invoke([this](int group_id) { return (int)(addresses_.size()); }));
+
     // Support 2M Phy
     ON_CALL(mock_controller_, SupportsBle2mPhy()).WillByDefault(Return(true));
     ON_CALL(btm_interface, IsPhy2mSupported(_, _)).WillByDefault(Return(true));
@@ -445,6 +463,7 @@
       ase_ctp_handlers[i] = nullptr;
 
     le_audio_devices_.clear();
+    addresses_.clear();
     cached_codec_configuration_map_.clear();
     cached_ase_to_cis_id_map_.clear();
     LeAudioGroupStateMachine::Cleanup();
@@ -492,6 +511,7 @@
     }
 
     le_audio_devices_.push_back(leAudioDevice);
+    addresses_.push_back(leAudioDevice->address_);
 
     return std::move(leAudioDevice);
   }
@@ -511,10 +531,9 @@
     return &(*group);
   }
 
-  static void InjectAseStateNotification(types::ase* ase, LeAudioDevice* device,
-                                         LeAudioDeviceGroup* group,
-                                         uint8_t new_state,
-                                         void* new_state_params) {
+  void InjectAseStateNotification(types::ase* ase, LeAudioDevice* device,
+                                  LeAudioDeviceGroup* group, uint8_t new_state,
+                                  void* new_state_params) {
     // Prepare additional params
     switch (new_state) {
       case ascs::kAseStateCodecConfigured: {
@@ -661,7 +680,7 @@
     });
   }
 
-  static void InjectInitialIdleNotification(LeAudioDeviceGroup* group) {
+  void InjectInitialIdleNotification(LeAudioDeviceGroup* group) {
     for (auto* device = group->GetFirstDevice(); device != nullptr;
          device = group->GetNextDevice(device)) {
       for (auto& ase : device->ases_) {
@@ -686,18 +705,18 @@
     uint8_t num_ase_src;
     switch (context_type) {
       case kContextTypeRingtone:
-        num_ase_snk = 1 + additional_ases;
-        num_ase_src = 0;
+        num_ase_snk = 1 + additional_snk_ases;
+        num_ase_src = 0 + additional_src_ases;
         break;
 
       case kContextTypeMedia:
-        num_ase_snk = 2 + additional_ases;
-        num_ase_src = 0;
+        num_ase_snk = 2 + additional_snk_ases;
+        num_ase_src = 0 + additional_src_ases;
         break;
 
       case kContextTypeConversational:
-        num_ase_snk = 1 + additional_ases;
-        num_ase_src = 1;
+        num_ase_snk = 1 + additional_snk_ases;
+        num_ase_src = 1 + additional_src_ases;
         break;
 
       default:
@@ -941,7 +960,7 @@
   void PrepareEnableHandler(LeAudioDeviceGroup* group, int verify_ase_count = 0,
                             bool inject_enabling = true) {
     ase_ctp_handlers[ascs::kAseCtpOpcodeEnable] =
-        [group, verify_ase_count, inject_enabling](
+        [group, verify_ase_count, inject_enabling, this](
             LeAudioDevice* device, std::vector<uint8_t> value,
             GATT_WRITE_OP_CB cb, void* cb_data) {
           auto num_ase = value[1];
@@ -989,9 +1008,9 @@
   void PrepareDisableHandler(LeAudioDeviceGroup* group,
                              int verify_ase_count = 0) {
     ase_ctp_handlers[ascs::kAseCtpOpcodeDisable] =
-        [group, verify_ase_count](LeAudioDevice* device,
-                                  std::vector<uint8_t> value,
-                                  GATT_WRITE_OP_CB cb, void* cb_data) {
+        [group, verify_ase_count, this](LeAudioDevice* device,
+                                        std::vector<uint8_t> value,
+                                        GATT_WRITE_OP_CB cb, void* cb_data) {
           auto num_ase = value[1];
 
           // Verify ase count if needed
@@ -1035,9 +1054,9 @@
   void PrepareReceiverStartReady(LeAudioDeviceGroup* group,
                                  int verify_ase_count = 0) {
     ase_ctp_handlers[ascs::kAseCtpOpcodeReceiverStartReady] =
-        [group, verify_ase_count](LeAudioDevice* device,
-                                  std::vector<uint8_t> value,
-                                  GATT_WRITE_OP_CB cb, void* cb_data) {
+        [group, verify_ase_count, this](LeAudioDevice* device,
+                                        std::vector<uint8_t> value,
+                                        GATT_WRITE_OP_CB cb, void* cb_data) {
           auto num_ase = value[1];
 
           // Verify ase count if needed
@@ -1073,9 +1092,9 @@
   void PrepareReceiverStopReady(LeAudioDeviceGroup* group,
                                 int verify_ase_count = 0) {
     ase_ctp_handlers[ascs::kAseCtpOpcodeReceiverStopReady] =
-        [group, verify_ase_count](LeAudioDevice* device,
-                                  std::vector<uint8_t> value,
-                                  GATT_WRITE_OP_CB cb, void* cb_data) {
+        [group, verify_ase_count, this](LeAudioDevice* device,
+                                        std::vector<uint8_t> value,
+                                        GATT_WRITE_OP_CB cb, void* cb_data) {
           auto num_ase = value[1];
 
           // Verify ase count if needed
@@ -1143,6 +1162,7 @@
         };
   }
 
+  MockCsisClient mock_csis_client_module_;
   NiceMock<controller::MockControllerInterface> mock_controller_;
   NiceMock<bluetooth::manager::MockBtmInterface> btm_interface;
   gatt::MockBtaGattInterface gatt_interface;
@@ -1163,6 +1183,7 @@
 
   MockLeAudioGroupStateMachineCallbacks mock_callbacks_;
   std::vector<std::shared_ptr<LeAudioDevice>> le_audio_devices_;
+  std::vector<RawAddress> addresses_;
   std::map<uint8_t, std::unique_ptr<LeAudioDeviceGroup>>
       le_audio_device_groups_;
   bool group_create_command_disallowed_ = false;
@@ -1179,6 +1200,9 @@
 }
 
 TEST_F(StateMachineTest, testConfigureCodecSingle) {
+  /* Device is banded headphones with 1x snk + 0x src ase
+   * (1xunidirectional CIS) with channel count 2 (for stereo
+   */
   const auto context_type = kContextTypeRingtone;
   const int leaudio_group_id = 2;
   channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel |
@@ -1259,6 +1283,11 @@
 }
 
 TEST_F(StateMachineTest, testConfigureQosSingle) {
+  /* Device is banded headphones with 2x snk + 1x src ase
+   * (1x bidirectional + 1xunidirectional CIS)
+   */
+  additional_snk_ases = 1;
+  additional_src_ases = 1;
   const auto context_type = kContextTypeRingtone;
   const int leaudio_group_id = 3;
 
@@ -1269,8 +1298,8 @@
    * should have been configured.
    */
   auto* leAudioDevice = group->GetFirstDevice();
-  PrepareConfigureCodecHandler(group, 1);
-  PrepareConfigureQosHandler(group, 1);
+  PrepareConfigureCodecHandler(group, 2);
+  PrepareConfigureQosHandler(group, 2);
 
   // Start the configuration and stream Media content
   EXPECT_CALL(gatt_queue,
@@ -1296,6 +1325,11 @@
 }
 
 TEST_F(StateMachineTest, testConfigureQosSingleRecoverCig) {
+  /* Device is banded headphones with 2x snk + 1x src ase
+   * (1x bidirectional + 1xunidirectional CIS)
+   */
+  additional_snk_ases = 1;
+  additional_src_ases = 1;
   const auto context_type = kContextTypeRingtone;
   const int leaudio_group_id = 3;
 
@@ -1309,8 +1343,8 @@
    * should have been configured.
    */
   auto* leAudioDevice = group->GetFirstDevice();
-  PrepareConfigureCodecHandler(group, 1);
-  PrepareConfigureQosHandler(group, 1);
+  PrepareConfigureCodecHandler(group, 2);
+  PrepareConfigureQosHandler(group, 2);
 
   // Start the configuration and stream Media content
   EXPECT_CALL(gatt_queue,
@@ -1382,14 +1416,19 @@
 }
 
 TEST_F(StateMachineTest, testStreamSingle) {
+  /* Device is banded headphones with 1x snk + 0x src ase
+   * (1xunidirectional CIS) with channel count 2 (for stereo
+   */
   const auto context_type = kContextTypeRingtone;
   const int leaudio_group_id = 4;
+  channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel |
+                   kLeAudioCodecLC3ChannelCountTwoChannel;
 
   // Prepare fake connected device group
   auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
 
-  /* Since we prepared device with Ringtone context in mind, only one ASE
-   * should have been configured.
+  /* Ringtone with channel count 1 for single device and 1 ASE sink will
+   * end up with 1 Sink ASE being configured.
    */
   PrepareConfigureCodecHandler(group, 1);
   PrepareConfigureQosHandler(group, 1);
@@ -1427,18 +1466,21 @@
 }
 
 TEST_F(StateMachineTest, testStreamSkipEnablingSink) {
-  const auto context_type = kContextTypeRingtone;
+  /* Device is banded headphones with 2x snk + none src ase
+   * (2x unidirectional CIS)
+   */
+  const auto context_type = kContextTypeMedia;
   const int leaudio_group_id = 4;
 
   // Prepare fake connected device group
   auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
 
-  /* Since we prepared device with Ringtone context in mind, only one ASE
-   * should have been configured.
+  /* For Media context type with channel count 1 and two ASEs,
+   * there should have be 2 Ases configured configured.
    */
-  PrepareConfigureCodecHandler(group, 1);
-  PrepareConfigureQosHandler(group, 1);
-  PrepareEnableHandler(group, 1, false);
+  PrepareConfigureCodecHandler(group, 2);
+  PrepareConfigureQosHandler(group, 2);
+  PrepareEnableHandler(group, 2, false);
 
   auto* leAudioDevice = group->GetFirstDevice();
   EXPECT_CALL(gatt_queue,
@@ -1448,7 +1490,7 @@
 
   EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
   EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
-  EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(1);
+  EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
   EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
   EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
   EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
@@ -1472,18 +1514,23 @@
 }
 
 TEST_F(StateMachineTest, testStreamSkipEnablingSinkSource) {
+  /* Device is banded headphones with 2x snk + 1x src ase
+   * (1x bidirectional CIS)
+   */
   const auto context_type = kContextTypeConversational;
   const int leaudio_group_id = 4;
 
+  additional_snk_ases = 1;
+
   // Prepare fake connected device group
   auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
 
-  /* Since we prepared device with Conversional context in mind, one Sink ASE
-   * and one Source ASE should have been configured.
+  /* Since we prepared device with Conversional context in mind,
+   * 2 Sink ASEs and 1 Source ASE should have been configured.
    */
-  PrepareConfigureCodecHandler(group, 2);
-  PrepareConfigureQosHandler(group, 2);
-  PrepareEnableHandler(group, 2, false);
+  PrepareConfigureCodecHandler(group, 3);
+  PrepareConfigureQosHandler(group, 3);
+  PrepareEnableHandler(group, 3, false);
   PrepareReceiverStartReady(group, 1);
 
   auto* leAudioDevice = group->GetFirstDevice();
@@ -1494,7 +1541,7 @@
 
   EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
   EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
-  EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
+  EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(3);
   EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
   EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
   EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
@@ -1622,20 +1669,98 @@
             types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
 }
 
+TEST_F(StateMachineTest, testUpdateMetadataMultiple) {
+  const auto context_type = kContextTypeMedia;
+  const auto leaudio_group_id = 4;
+  const auto num_devices = 2;
+
+  // Prepare multiple fake connected devices in a group
+  auto* group =
+      PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
+  ASSERT_EQ(group->Size(), num_devices);
+
+  PrepareConfigureCodecHandler(group);
+  PrepareConfigureQosHandler(group);
+  PrepareEnableHandler(group);
+
+  EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
+  EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(AtLeast(1));
+  EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
+  EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
+  EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
+  EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
+
+  InjectInitialIdleNotification(group);
+
+  auto* leAudioDevice = group->GetFirstDevice();
+  auto expected_devices_written = 0;
+  while (leAudioDevice) {
+    EXPECT_CALL(gatt_queue,
+                WriteCharacteristic(leAudioDevice->conn_id_,
+                                    leAudioDevice->ctp_hdls_.val_hdl, _,
+                                    GATT_WRITE_NO_RSP, _, _))
+        .Times(AtLeast(3));
+    expected_devices_written++;
+    leAudioDevice = group->GetNextDevice(leAudioDevice);
+  }
+  ASSERT_EQ(expected_devices_written, num_devices);
+
+  // Validate GroupStreamStatus
+  EXPECT_CALL(
+      mock_callbacks_,
+      StatusReportCb(leaudio_group_id,
+                     bluetooth::le_audio::GroupStreamStatus::STREAMING));
+
+  // Start the configuration and stream Media content
+  ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
+      group, static_cast<LeAudioContextType>(context_type),
+      types::AudioContexts(context_type)));
+
+  testing::Mock::VerifyAndClearExpectations(&gatt_queue);
+
+  // Check if group has transitioned to a proper state
+  ASSERT_EQ(group->GetState(),
+            types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
+
+  // Make sure all devices get the metadata update
+  leAudioDevice = group->GetFirstDevice();
+  expected_devices_written = 0;
+  while (leAudioDevice) {
+    EXPECT_CALL(gatt_queue,
+                WriteCharacteristic(leAudioDevice->conn_id_,
+                                    leAudioDevice->ctp_hdls_.val_hdl, _,
+                                    GATT_WRITE_NO_RSP, _, _))
+        .Times(1);
+    expected_devices_written++;
+    leAudioDevice = group->GetNextDevice(leAudioDevice);
+  }
+  ASSERT_EQ(expected_devices_written, num_devices);
+
+  const auto metadata_context_type =
+      kContextTypeMedia | kContextTypeSoundEffects;
+  ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
+      group, static_cast<LeAudioContextType>(context_type),
+      metadata_context_type));
+}
+
 TEST_F(StateMachineTest, testDisableSingle) {
+  /* Device is banded headphones with 2x snk + 0x src ase
+   * (2xunidirectional CIS)
+   */
+  additional_snk_ases = 1;
   const auto context_type = kContextTypeRingtone;
   const int leaudio_group_id = 4;
 
   // Prepare fake connected device group
   auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
 
-  /* Since we prepared device with Ringtone context in mind, only one ASE
-   * should have been configured.
+  /* Ringtone context plus additional ASE with channel count 1
+   * gives us 2 ASE which should have been configured.
    */
-  PrepareConfigureCodecHandler(group, 1);
-  PrepareConfigureQosHandler(group, 1);
-  PrepareEnableHandler(group, 1);
-  PrepareDisableHandler(group, 1);
+  PrepareConfigureCodecHandler(group, 2);
+  PrepareConfigureQosHandler(group, 2);
+  PrepareEnableHandler(group, 2);
+  PrepareDisableHandler(group, 2);
 
   auto* leAudioDevice = group->GetFirstDevice();
   EXPECT_CALL(gatt_queue,
@@ -1645,13 +1770,13 @@
 
   EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
   EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
-  EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(1);
+  EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
   EXPECT_CALL(
       *mock_iso_manager_,
       RemoveIsoDataPath(
           _, bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionInput))
-      .Times(1);
-  EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(1);
+      .Times(2);
+  EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2);
   EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
 
   InjectInitialIdleNotification(group);
@@ -1752,6 +1877,10 @@
 }
 
 TEST_F(StateMachineTest, testDisableBidirectional) {
+  /* Device is banded headphones with 2x snk + 1x src ase
+   * (1x bidirectional + 1xunidirectional CIS)
+   */
+  additional_snk_ases = 1;
   const auto context_type = kContextTypeConversational;
   const int leaudio_group_id = 4;
 
@@ -1761,10 +1890,10 @@
   /* Since we prepared device with Conversional context in mind, Sink and Source
    * ASEs should have been configured.
    */
-  PrepareConfigureCodecHandler(group, 2);
-  PrepareConfigureQosHandler(group, 2);
-  PrepareEnableHandler(group, 2);
-  PrepareDisableHandler(group, 2);
+  PrepareConfigureCodecHandler(group, 3);
+  PrepareConfigureQosHandler(group, 3);
+  PrepareEnableHandler(group, 3);
+  PrepareDisableHandler(group, 3);
   PrepareReceiverStartReady(group, 1);
   PrepareReceiverStopReady(group, 1);
 
@@ -1776,15 +1905,48 @@
 
   EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
   EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
-  EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
-  EXPECT_CALL(
-      *mock_iso_manager_,
-      RemoveIsoDataPath(
-          _,
-          bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionInput |
-              bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionOutput))
-      .Times(1);
-  EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(1);
+  EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(3);
+  bool removed_bidirectional = false;
+  bool removed_unidirectional = false;
+
+  /* Check data path removal */
+  ON_CALL(*mock_iso_manager_, RemoveIsoDataPath)
+      .WillByDefault(Invoke([&removed_bidirectional, &removed_unidirectional,
+                             this](uint16_t conn_handle,
+                                   uint8_t data_path_dir) {
+        /* Set flags for verification */
+        if (data_path_dir ==
+            (bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionInput |
+             bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionOutput)) {
+          removed_bidirectional = true;
+        } else if (data_path_dir == bluetooth::hci::iso_manager::
+                                        kRemoveIsoDataPathDirectionInput) {
+          removed_unidirectional = true;
+        }
+
+        /* Copied from default handler of RemoveIsoDataPath*/
+        auto dev_it =
+            std::find_if(le_audio_devices_.begin(), le_audio_devices_.end(),
+                         [&conn_handle](auto& dev) {
+                           auto ases = dev->GetAsesByCisConnHdl(conn_handle);
+                           return (ases.sink || ases.source);
+                         });
+        if (dev_it == le_audio_devices_.end()) {
+          return;
+        }
+
+        for (auto& kv_pair : le_audio_device_groups_) {
+          auto& group = kv_pair.second;
+          if (group->IsDeviceInTheGroup(dev_it->get())) {
+            LeAudioGroupStateMachine::Get()->ProcessHciNotifRemoveIsoDataPath(
+                group.get(), dev_it->get(), 0, conn_handle);
+            return;
+          }
+        }
+        /* End of copy */
+      }));
+
+  EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2);
   EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
 
   // Start the configuration and stream Media content
@@ -1802,11 +1964,18 @@
   // Check if group has transitioned to a proper state
   ASSERT_EQ(group->GetState(),
             types::AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED);
+  ASSERT_EQ(removed_bidirectional, true);
+  ASSERT_EQ(removed_unidirectional, true);
 }
 
 TEST_F(StateMachineTest, testReleaseSingle) {
+  /* Device is banded headphones with 1x snk + 0x src ase
+   * (1xunidirectional CIS) with channel count 2 (for stereo)
+   */
   const auto context_type = kContextTypeRingtone;
   const int leaudio_group_id = 4;
+  channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel |
+                   kLeAudioCodecLC3ChannelCountTwoChannel;
 
   // Prepare fake connected device group
   auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
@@ -1861,8 +2030,13 @@
 }
 
 TEST_F(StateMachineTest, testReleaseCachingSingle) {
+  /* Device is banded headphones with 1x snk + 0x src ase
+   * (1xunidirectional CIS)
+   */
   const auto context_type = kContextTypeRingtone;
   const int leaudio_group_id = 4;
+  channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel |
+                   kLeAudioCodecLC3ChannelCountTwoChannel;
 
   // Prepare fake connected device group
   auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
@@ -1931,7 +2105,7 @@
   channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel |
                    kLeAudioCodecLC3ChannelCountTwoChannel;
 
-  additional_ases = 2;
+  additional_snk_ases = 2;
   // Prepare fake connected device group
   auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
 
@@ -2017,7 +2191,7 @@
   channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel |
                    kLeAudioCodecLC3ChannelCountTwoChannel;
 
-  additional_ases = 2;
+  additional_snk_ases = 2;
   /* Prepare fake connected device group with update of Media and Conversational
    * contexts
    */
@@ -2175,6 +2349,10 @@
 }
 
 TEST_F(StateMachineTest, testReleaseBidirectional) {
+  /* Device is banded headphones with 2x snk + 1x src ase
+   * (1x bidirectional + 1xunidirectional CIS)
+   */
+  additional_snk_ases = 1;
   const auto context_type = kContextTypeConversational;
   const auto leaudio_group_id = 6;
 
@@ -2184,12 +2362,12 @@
   /* Since we prepared device with Conversional context in mind, Sink and Source
    * ASEs should have been configured.
    */
-  PrepareConfigureCodecHandler(group, 2);
-  PrepareConfigureQosHandler(group, 2);
-  PrepareEnableHandler(group, 2);
-  PrepareDisableHandler(group, 2);
+  PrepareConfigureCodecHandler(group, 3);
+  PrepareConfigureQosHandler(group, 3);
+  PrepareEnableHandler(group, 3);
+  PrepareDisableHandler(group, 3);
   PrepareReceiverStartReady(group, 1);
-  PrepareReleaseHandler(group, 2);
+  PrepareReleaseHandler(group, 3);
 
   auto* leAudioDevice = group->GetFirstDevice();
   EXPECT_CALL(gatt_queue,
@@ -2199,9 +2377,9 @@
 
   EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
   EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
-  EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
-  EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(1);
-  EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(1);
+  EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(3);
+  EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(2);
+  EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2);
   EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1);
 
   InjectInitialIdleNotification(group);
@@ -2223,6 +2401,10 @@
 }
 
 TEST_F(StateMachineTest, testDisableAndReleaseBidirectional) {
+  /* Device is banded headphones with 2x snk + 1x src ase
+   * (1x bidirectional + 1xunidirectional CIS)
+   */
+  additional_snk_ases = 1;
   const auto context_type = kContextTypeConversational;
   const int leaudio_group_id = 4;
 
@@ -2232,13 +2414,13 @@
   /* Since we prepared device with Conversional context in mind, Sink and Source
    * ASEs should have been configured.
    */
-  PrepareConfigureCodecHandler(group, 2);
-  PrepareConfigureQosHandler(group, 2);
-  PrepareEnableHandler(group, 2);
-  PrepareDisableHandler(group, 2);
+  PrepareConfigureCodecHandler(group, 3);
+  PrepareConfigureQosHandler(group, 3);
+  PrepareEnableHandler(group, 3);
+  PrepareDisableHandler(group, 3);
   PrepareReceiverStartReady(group, 1);
   PrepareReceiverStopReady(group, 1);
-  PrepareReleaseHandler(group, 2);
+  PrepareReleaseHandler(group, 3);
 
   auto* leAudioDevice = group->GetFirstDevice();
   EXPECT_CALL(gatt_queue,
@@ -2248,9 +2430,9 @@
 
   EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
   EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
-  EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
-  EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(1);
-  EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(1);
+  EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(3);
+  EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(2);
+  EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2);
   EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1);
 
   // Start the configuration and stream Media content
@@ -2333,6 +2515,10 @@
 }
 
 TEST_F(StateMachineTest, testAseAutonomousRelease) {
+  /* Device is banded headphones with 2x snk + 1x src ase
+   * (1x bidirectional + 1xunidirectional CIS)
+   */
+  additional_snk_ases = 1;
   const auto context_type = kContextTypeConversational;
   const int leaudio_group_id = 4;
 
@@ -2342,13 +2528,13 @@
   /* Since we prepared device with Conversional context in mind, Sink and Source
    * ASEs should have been configured.
    */
-  PrepareConfigureCodecHandler(group, 2);
-  PrepareConfigureQosHandler(group, 2);
-  PrepareEnableHandler(group, 2);
-  PrepareDisableHandler(group, 2);
+  PrepareConfigureCodecHandler(group, 3);
+  PrepareConfigureQosHandler(group, 3);
+  PrepareEnableHandler(group, 3);
+  PrepareDisableHandler(group, 3);
   PrepareReceiverStartReady(group, 1);
   PrepareReceiverStopReady(group, 1);
-  PrepareReleaseHandler(group, 2);
+  PrepareReleaseHandler(group, 3);
 
   InjectInitialIdleNotification(group);
 
@@ -2370,7 +2556,7 @@
       .Times(AtLeast(1));
 
   /* Single disconnect as it is bidirectional Cis*/
-  EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(1);
+  EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2);
 
   for (auto* device = group->GetFirstDevice(); device != nullptr;
        device = group->GetNextDevice(device)) {
@@ -2457,6 +2643,8 @@
 TEST_F(StateMachineTest, testStateTransitionTimeoutOnIdleState) {
   const auto context_type = kContextTypeRingtone;
   const int leaudio_group_id = 4;
+  channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel |
+                   kLeAudioCodecLC3ChannelCountTwoChannel;
 
   // Prepare fake connected device group
   auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
@@ -2483,6 +2671,8 @@
 TEST_F(StateMachineTest, testStateTransitionTimeout) {
   const auto context_type = kContextTypeRingtone;
   const int leaudio_group_id = 4;
+  channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel |
+                   kLeAudioCodecLC3ChannelCountTwoChannel;
 
   // Prepare fake connected device group
   auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
@@ -2517,6 +2707,8 @@
 TEST_F(StateMachineTest, testConfigureDataPathForHost) {
   const auto context_type = kContextTypeRingtone;
   const int leaudio_group_id = 4;
+  channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel |
+                   kLeAudioCodecLC3ChannelCountTwoChannel;
 
   /* Should be called 3 times because
    * 1 - calling GetConfigurations just after connection
@@ -2555,6 +2747,8 @@
 TEST_F(StateMachineTest, testConfigureDataPathForAdsp) {
   const auto context_type = kContextTypeRingtone;
   const int leaudio_group_id = 4;
+  channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel |
+                   kLeAudioCodecLC3ChannelCountTwoChannel;
 
   /* Should be called 3 times because
    * 1 - calling GetConfigurations just after connection
@@ -2959,7 +3153,8 @@
 
   sample_freq_ |= codec_specific::kCapSamplingFrequency48000Hz |
                   codec_specific::kCapSamplingFrequency32000Hz;
-  additional_ases = 3;
+  additional_snk_ases = 3;
+  additional_src_ases = 1;
 
   ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
   ContentControlIdKeeper::GetInstance()->SetCcid(call_context, call_ccid);
@@ -3039,5 +3234,97 @@
 
   testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
 }
+
+TEST_F(StateMachineTest, BoundedHeadphonesConversationalToMediaChannelCount_1) {
+  const auto initial_context_type = kContextTypeConversational;
+  const auto new_context_type = kContextTypeMedia;
+  const auto leaudio_group_id = 6;
+  const auto num_devices = 1;
+  channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel;
+
+  sample_freq_ |= codec_specific::kCapSamplingFrequency48000Hz |
+                  codec_specific::kCapSamplingFrequency32000Hz;
+  additional_snk_ases = 3;
+  additional_src_ases = 1;
+
+  ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
+  ContentControlIdKeeper::GetInstance()->SetCcid(call_context, call_ccid);
+
+  // Prepare one fake connected devices in a group
+  auto* group = PrepareSingleTestDeviceGroup(
+      leaudio_group_id, initial_context_type, num_devices,
+      kContextTypeConversational | kContextTypeMedia);
+  ASSERT_EQ(group->Size(), num_devices);
+
+  // Cannot verify here as we will change the number of ases on reconfigure
+  PrepareConfigureCodecHandler(group, 0, true);
+  PrepareConfigureQosHandler(group);
+  PrepareEnableHandler(group);
+  PrepareDisableHandler(group);
+  PrepareReleaseHandler(group);
+  PrepareReceiverStartReady(group);
+
+  InjectInitialIdleNotification(group);
+
+  auto* leAudioDevice = group->GetFirstDevice();
+  auto expected_devices_written = 0;
+  while (leAudioDevice) {
+    /* 8 Writes:
+     * 1: Codec config (+1 after reconfig)
+     * 2: Codec QoS (+1 after reconfig)
+     * 3: Enabling (+1 after reconfig)
+     * 4: ReceiverStartReady (only for conversational)
+     * 5: Release
+     */
+    EXPECT_CALL(gatt_queue,
+                WriteCharacteristic(leAudioDevice->conn_id_,
+                                    leAudioDevice->ctp_hdls_.val_hdl, _,
+                                    GATT_WRITE_NO_RSP, _, _))
+        .Times(8);
+    expected_devices_written++;
+    leAudioDevice = group->GetNextDevice(leAudioDevice);
+  }
+  ASSERT_EQ(expected_devices_written, num_devices);
+
+  // Validate GroupStreamStatus
+  EXPECT_CALL(
+      mock_callbacks_,
+      StatusReportCb(leaudio_group_id,
+                     bluetooth::le_audio::GroupStreamStatus::STREAMING));
+
+  // Start the configuration and stream Media content
+  LeAudioGroupStateMachine::Get()->StartStream(
+      group, initial_context_type, types::AudioContexts(initial_context_type));
+
+  testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
+
+  // Validate GroupStreamStatus
+  EXPECT_CALL(
+      mock_callbacks_,
+      StatusReportCb(leaudio_group_id,
+                     bluetooth::le_audio::GroupStreamStatus::RELEASING));
+
+  EXPECT_CALL(
+      mock_callbacks_,
+      StatusReportCb(
+          leaudio_group_id,
+          bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS));
+  // Start the configuration and stream Media content
+  LeAudioGroupStateMachine::Get()->StopStream(group);
+
+  testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
+
+  // Restart stream
+  EXPECT_CALL(
+      mock_callbacks_,
+      StatusReportCb(leaudio_group_id,
+                     bluetooth::le_audio::GroupStreamStatus::STREAMING));
+
+  // Start the configuration and stream Media content
+  LeAudioGroupStateMachine::Get()->StartStream(
+      group, new_context_type, types::AudioContexts(new_context_type));
+
+  testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
+}
 }  // namespace internal
 }  // namespace le_audio
diff --git a/system/bta/test/common/mock_csis_client.h b/system/bta/test/common/mock_csis_client.h
index 33c106a..bd28233 100644
--- a/system/bta/test/common/mock_csis_client.h
+++ b/system/bta/test/common/mock_csis_client.h
@@ -33,6 +33,7 @@
               (override));
   MOCK_METHOD((std::vector<RawAddress>), GetDeviceList, (int group_id),
               (override));
+  MOCK_METHOD((int), GetDesiredSize, (int group_id), (override));
 
   /* Called from static methods */
   MOCK_METHOD((void), Initialize,
diff --git a/system/main/shim/l2c_api.h b/system/main/shim/l2c_api.h
index 0fe3fbd..c70b913 100644
--- a/system/main/shim/l2c_api.h
+++ b/system/main/shim/l2c_api.h
@@ -428,6 +428,8 @@
  ******************************************************************************/
 bool L2CA_SetLeGattTimeout(const RawAddress& rem_bda, uint16_t idle_tout);
 
+bool L2CA_MarkLeLinkAsActive(const RawAddress& rem_bda);
+
 bool L2CA_UpdateBleConnParams(const RawAddress& rem_bda, uint16_t min_int,
                               uint16_t max_int, uint16_t latency,
                               uint16_t timeout, uint16_t min_ce_len,
diff --git a/system/stack/gatt/gatt_api.cc b/system/stack/gatt/gatt_api.cc
index 0e3c23e..91bcb1e 100644
--- a/system/stack/gatt/gatt_api.cc
+++ b/system/stack/gatt/gatt_api.cc
@@ -1037,26 +1037,36 @@
  *
  * Parameter        bd_addr:   target device bd address.
  *                  idle_tout: timeout value in seconds.
+ *                  transport: transport option.
+ *                  is_active: whether we should use this as a signal that an
+ *                             active client now exists (which changes link
+ *                             timeout logic, see
+ *                             t_l2c_linkcb.with_active_local_clients for
+ *                             details).
  *
  * Returns          void
  *
  ******************************************************************************/
 void GATT_SetIdleTimeout(const RawAddress& bd_addr, uint16_t idle_tout,
-                         tBT_TRANSPORT transport) {
+                         tBT_TRANSPORT transport, bool is_active) {
   bool status = false;
 
   tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bd_addr, transport);
   if (p_tcb != nullptr) {
     status = L2CA_SetLeGattTimeout(bd_addr, idle_tout);
 
+    if (is_active) {
+      status &= L2CA_MarkLeLinkAsActive(bd_addr);
+    }
+
     if (idle_tout == GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP) {
       L2CA_SetIdleTimeoutByBdAddr(
           p_tcb->peer_bda, GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP, BT_TRANSPORT_LE);
     }
   }
 
-  LOG_INFO("idle_timeout=%d, status=%d, (1-OK 0-not performed)", idle_tout,
-           +status);
+  LOG_INFO("idle_timeout=%d, is_active=%d, status=%d (1-OK 0-not performed)",
+           idle_tout, is_active, +status);
 }
 
 /*******************************************************************************
diff --git a/system/stack/gatt/gatt_main.cc b/system/stack/gatt/gatt_main.cc
index 92c6a77..0550d4a 100644
--- a/system/stack/gatt/gatt_main.cc
+++ b/system/stack/gatt/gatt_main.cc
@@ -114,10 +114,11 @@
   fixed_reg.pL2CA_FixedConn_Cb = gatt_le_connect_cback;
   fixed_reg.pL2CA_FixedData_Cb = gatt_le_data_ind;
   fixed_reg.pL2CA_FixedCong_Cb = gatt_le_cong_cback; /* congestion callback */
-  fixed_reg.default_idle_tout =
-      bluetooth::common::init_flags::finite_att_timeout_is_enabled()
-          ? 2 /* We allow 2s for GATT clients to connect once the link is up */
-          : L2CAP_NO_IDLE_TIMEOUT;
+
+  // the GATT timeout is updated after a connection
+  // is established, when we know whether any
+  // clients exist
+  fixed_reg.default_idle_tout = L2CAP_NO_IDLE_TIMEOUT;
 
   L2CA_RegisterFixedChannel(L2CAP_ATT_CID, &fixed_reg);
 
@@ -376,7 +377,7 @@
                p_tcb->peer_bda.ToString().c_str());
       /* acl link is connected disable the idle timeout */
       GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_NO_IDLE_TIMEOUT,
-                          p_tcb->transport);
+                          p_tcb->transport, true /* is_active */);
     } else {
       LOG_INFO("invalid handle %d or dynamic CID %d", is_valid_handle,
                p_tcb->att_lcid);
@@ -395,7 +396,7 @@
             "%d seconds",
             GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP);
         GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP,
-                            p_tcb->transport);
+                            p_tcb->transport, false /* is_active */);
       } else {
         // disconnect the dynamic channel
         LOG_INFO("disconnect GATT dynamic channel");
@@ -819,11 +820,18 @@
   /* Remove the direct connection */
   connection_manager::on_connection_complete(p_tcb->peer_bda);
 
-  if (!p_tcb->app_hold_link.empty() && p_tcb->att_lcid == L2CAP_ATT_CID) {
-    /* disable idle timeout if one or more clients are holding the link disable
-     * the idle timer */
-    GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_NO_IDLE_TIMEOUT,
-                        p_tcb->transport);
+  if (p_tcb->att_lcid == L2CAP_ATT_CID) {
+    if (!p_tcb->app_hold_link.empty()) {
+      /* disable idle timeout if one or more clients are holding the link
+       * disable the idle timer */
+      GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_NO_IDLE_TIMEOUT,
+                          p_tcb->transport, true /* is_active */);
+    } else {
+      if (bluetooth::common::init_flags::finite_att_timeout_is_enabled()) {
+        GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP,
+                            p_tcb->transport, false /* is_active */);
+      }
+    }
   }
 }
 
diff --git a/system/stack/include/gatt_api.h b/system/stack/include/gatt_api.h
index 1bb3d07..4486771 100644
--- a/system/stack/include/gatt_api.h
+++ b/system/stack/include/gatt_api.h
@@ -999,13 +999,18 @@
  *
  * Parameter        bd_addr:   target device bd address.
  *                  idle_tout: timeout value in seconds.
- *                  transport: trasnport option.
+ *                  transport: transport option.
+ *                  is_active: whether we should use this as a signal that an
+ *                             active client now exists (which changes link
+ *                             timeout logic, see
+ *                             t_l2c_linkcb.with_active_local_clients for
+ *                             details).
  *
  * Returns          void
  *
  ******************************************************************************/
 extern void GATT_SetIdleTimeout(const RawAddress& bd_addr, uint16_t idle_tout,
-                                tBT_TRANSPORT transport);
+                                tBT_TRANSPORT transport, bool is_active);
 
 /*******************************************************************************
  *
diff --git a/system/stack/include/l2c_api.h b/system/stack/include/l2c_api.h
index 42688d2..d62da3c 100644
--- a/system/stack/include/l2c_api.h
+++ b/system/stack/include/l2c_api.h
@@ -842,6 +842,8 @@
 extern bool L2CA_SetLeGattTimeout(const RawAddress& rem_bda,
                                   uint16_t idle_tout);
 
+extern bool L2CA_MarkLeLinkAsActive(const RawAddress& rem_bda);
+
 extern bool L2CA_UpdateBleConnParams(const RawAddress& rem_bda,
                                      uint16_t min_int, uint16_t max_int,
                                      uint16_t latency, uint16_t timeout,
diff --git a/system/stack/l2cap/l2c_api.cc b/system/stack/l2cap/l2c_api.cc
index 492a379..5464cb4 100644
--- a/system/stack/l2cap/l2c_api.cc
+++ b/system/stack/l2cap/l2c_api.cc
@@ -1558,6 +1558,16 @@
   return true;
 }
 
+bool L2CA_MarkLeLinkAsActive(const RawAddress& rem_bda) {
+  tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(rem_bda, BT_TRANSPORT_LE);
+  if (p_lcb == NULL) {
+    return false;
+  }
+  LOG(INFO) << __func__ << "setting link to " << rem_bda << " as active";
+  p_lcb->with_active_local_clients = true;
+  return true;
+}
+
 /*******************************************************************************
  *
  * Function         L2CA_DataWrite
diff --git a/system/stack/l2cap/l2c_int.h b/system/stack/l2cap/l2c_int.h
index ac02e95..a5ba258 100644
--- a/system/stack/l2cap/l2c_int.h
+++ b/system/stack/l2cap/l2c_int.h
@@ -428,6 +428,13 @@
   tL2C_LINK_STATE link_state;
 
   alarm_t* l2c_lcb_timer; /* Timer entry for timeout evt */
+
+  //  This tracks if the link has ever either (a)
+  //  been used for a dynamic channel (EATT or L2CAP CoC), or (b) has been a
+  //  GATT client. If false, the local device is just a GATT server, so for
+  //  backwards compatibility we never do a link timeout.
+  bool with_active_local_clients{false};
+
  private:
   uint16_t handle_; /* The handle used with LM */
   friend void l2cu_set_lcb_handle(struct t_l2c_linkcb& p_lcb, uint16_t handle);
diff --git a/system/stack/l2cap/l2c_utils.cc b/system/stack/l2cap/l2c_utils.cc
index 6ffd13c..d903905 100755
--- a/system/stack/l2cap/l2c_utils.cc
+++ b/system/stack/l2cap/l2c_utils.cc
@@ -68,6 +68,7 @@
       p_lcb->remote_bd_addr = p_bd_addr;
 
       p_lcb->in_use = true;
+      p_lcb->with_active_local_clients = false;
       p_lcb->link_state = LST_DISCONNECTED;
       p_lcb->InvalidateHandle();
       p_lcb->l2c_lcb_timer = alarm_new("l2c_lcb.l2c_lcb_timer");
@@ -1350,7 +1351,7 @@
  *
  ******************************************************************************/
 tL2C_CCB* l2cu_allocate_ccb(tL2C_LCB* p_lcb, uint16_t cid) {
-  LOG_DEBUG("cid 0x%04x", cid);
+  LOG_DEBUG("is_dynamic = %d, cid 0x%04x", p_lcb != nullptr, cid);
   if (!l2cb.p_free_ccb_first) {
     LOG_ERROR("First free ccb is null for cid 0x%04x", cid);
     return nullptr;
@@ -1467,6 +1468,11 @@
 
   l2c_link_adjust_chnl_allocation();
 
+  if (p_lcb != NULL) {
+    // once a dynamic channel is opened, timeouts become active
+    p_lcb->with_active_local_clients = true;
+  }
+
   return p_ccb;
 }
 
@@ -2605,11 +2611,11 @@
   for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++) {
     if ((p_lcb->p_fixed_ccbs[xx] != NULL) &&
         (p_lcb->p_fixed_ccbs[xx]->fixed_chnl_idle_tout * 1000 > timeout_ms)) {
-
-      if (p_lcb->p_fixed_ccbs[xx]->fixed_chnl_idle_tout == L2CAP_NO_IDLE_TIMEOUT) {
-         L2CAP_TRACE_DEBUG("%s NO IDLE timeout set for fixed cid 0x%04x", __func__,
-            p_lcb->p_fixed_ccbs[xx]->local_cid);
-         start_timeout = false;
+      if (p_lcb->p_fixed_ccbs[xx]->fixed_chnl_idle_tout ==
+          L2CAP_NO_IDLE_TIMEOUT) {
+        L2CAP_TRACE_DEBUG("%s NO IDLE timeout set for fixed cid 0x%04x",
+                          __func__, p_lcb->p_fixed_ccbs[xx]->local_cid);
+        start_timeout = false;
       }
       timeout_ms = p_lcb->p_fixed_ccbs[xx]->fixed_chnl_idle_tout * 1000;
     }
@@ -2618,6 +2624,24 @@
   /* If the link is pairing, do not mess with the timeouts */
   if (p_lcb->IsBonding()) return;
 
+  L2CAP_TRACE_DEBUG("l2cu_no_dynamic_ccbs() with_active_local_clients=%d",
+                    p_lcb->with_active_local_clients);
+  // Inactive connections should not timeout, since the ATT channel might still
+  // be in use even without a GATT client. We only timeout if either a dynamic
+  // channel or a GATT client was used, since then we expect the client to
+  // manage the lifecycle of the connection.
+
+  // FOR T ONLY: We add the outer safety-check to only do this for LE/ATT, to
+  // minimize behavioral changes outside a dessert release. But for consistency
+  // this should happen throughout on U (i.e. for classic transport + other
+  // fixed channels too)
+  if (p_lcb->p_fixed_ccbs[L2CAP_ATT_CID - L2CAP_FIRST_FIXED_CHNL] != NULL) {
+    if (bluetooth::common::init_flags::finite_att_timeout_is_enabled() &&
+        !p_lcb->with_active_local_clients) {
+      return;
+    }
+  }
+
   if (timeout_ms == 0) {
     L2CAP_TRACE_DEBUG(
         "l2cu_no_dynamic_ccbs() IDLE timer 0, disconnecting link");
diff --git a/system/test/mock/mock_stack_gatt_api.cc b/system/test/mock/mock_stack_gatt_api.cc
index 2c40b7c..5a29c42 100644
--- a/system/test/mock/mock_stack_gatt_api.cc
+++ b/system/test/mock/mock_stack_gatt_api.cc
@@ -207,10 +207,10 @@
                                                    eatt_support);
 }
 void GATT_SetIdleTimeout(const RawAddress& bd_addr, uint16_t idle_tout,
-                         tBT_TRANSPORT transport) {
+                         tBT_TRANSPORT transport, bool is_active) {
   mock_function_count_map[__func__]++;
-  test::mock::stack_gatt_api::GATT_SetIdleTimeout(bd_addr, idle_tout,
-                                                  transport);
+  test::mock::stack_gatt_api::GATT_SetIdleTimeout(bd_addr, idle_tout, transport,
+                                                  is_active);
 }
 void GATT_StartIf(tGATT_IF gatt_if) {
   mock_function_count_map[__func__]++;
diff --git a/system/test/mock/mock_stack_gatt_api.h b/system/test/mock/mock_stack_gatt_api.h
index 2e8a473..0c34693 100644
--- a/system/test/mock/mock_stack_gatt_api.h
+++ b/system/test/mock/mock_stack_gatt_api.h
@@ -365,12 +365,12 @@
 // transport Return: void
 struct GATT_SetIdleTimeout {
   std::function<void(const RawAddress& bd_addr, uint16_t idle_tout,
-                     tBT_TRANSPORT transport)>
+                     tBT_TRANSPORT transport, bool is_active)>
       body{[](const RawAddress& bd_addr, uint16_t idle_tout,
-              tBT_TRANSPORT transport) {}};
+              tBT_TRANSPORT transport, bool is_active) {}};
   void operator()(const RawAddress& bd_addr, uint16_t idle_tout,
-                  tBT_TRANSPORT transport) {
-    body(bd_addr, idle_tout, transport);
+                  tBT_TRANSPORT transport, bool is_active) {
+    body(bd_addr, idle_tout, transport, is_active);
   };
 };
 extern struct GATT_SetIdleTimeout GATT_SetIdleTimeout;
diff --git a/system/test/mock/mock_stack_l2cap_api.cc b/system/test/mock/mock_stack_l2cap_api.cc
index 450753c..27cd1e3 100644
--- a/system/test/mock/mock_stack_l2cap_api.cc
+++ b/system/test/mock/mock_stack_l2cap_api.cc
@@ -93,6 +93,7 @@
 struct L2CA_SendFixedChnlData L2CA_SendFixedChnlData;
 struct L2CA_RemoveFixedChnl L2CA_RemoveFixedChnl;
 struct L2CA_SetLeGattTimeout L2CA_SetLeGattTimeout;
+struct L2CA_MarkLeLinkAsActive L2CA_MarkLeLinkAsActive;
 struct L2CA_DataWrite L2CA_DataWrite;
 struct L2CA_LECocDataWrite L2CA_LECocDataWrite;
 struct L2CA_SetChnlFlushability L2CA_SetChnlFlushability;
@@ -259,6 +260,10 @@
   mock_function_count_map[__func__]++;
   return test::mock::stack_l2cap_api::L2CA_SetLeGattTimeout(rem_bda, idle_tout);
 }
+bool L2CA_MarkLeLinkAsActive(const RawAddress& rem_bda) {
+  mock_function_count_map[__func__]++;
+  return test::mock::stack_l2cap_api::L2CA_MarkLeLinkAsActive(rem_bda);
+}
 uint8_t L2CA_DataWrite(uint16_t cid, BT_HDR* p_data) {
   mock_function_count_map[__func__]++;
   return test::mock::stack_l2cap_api::L2CA_DataWrite(cid, p_data);
diff --git a/system/test/mock/mock_stack_l2cap_api.h b/system/test/mock/mock_stack_l2cap_api.h
index fb0ef55..4488101 100644
--- a/system/test/mock/mock_stack_l2cap_api.h
+++ b/system/test/mock/mock_stack_l2cap_api.h
@@ -421,6 +421,15 @@
   };
 };
 extern struct L2CA_SetLeGattTimeout L2CA_SetLeGattTimeout;
+// Name: L2CA_MarkLeLinkAsActive
+// Params: const RawAddress& rem_bda
+// Returns: bool
+struct L2CA_MarkLeLinkAsActive {
+  std::function<bool(const RawAddress& rem_bda)> body{
+      [](const RawAddress& rem_bda) { return false; }};
+  bool operator()(const RawAddress& rem_bda) { return body(rem_bda); };
+};
+extern struct L2CA_MarkLeLinkAsActive L2CA_MarkLeLinkAsActive;
 // Name: L2CA_DataWrite
 // Params: uint16_t cid, BT_HDR* p_data
 // Returns: uint8_t