Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cc742584 authored by Jakub Pawłowski's avatar Jakub Pawłowski Committed by Automerger Merge Worker
Browse files

Merge "Synchronize group-related variables" am: 31057b09 am: dbb16f1c am:...

Merge "Synchronize group-related variables" am: 31057b09 am: dbb16f1c am: 765feabd am: 09747e21 am: 0d78de9d

Original change: https://android-review.googlesource.com/c/platform/packages/modules/Bluetooth/+/2049907



Change-Id: I859847dcbcb9d9506a2e7a1efae19b4d476c2d21
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents b33f6041 0d78de9d
Loading
Loading
Loading
Loading
+146 −111
Original line number Original line Diff line number Diff line
@@ -59,6 +59,7 @@ import com.android.bluetooth.btservice.ServiceFactory;
import com.android.bluetooth.btservice.storage.DatabaseManager;
import com.android.bluetooth.btservice.storage.DatabaseManager;
import com.android.bluetooth.mcp.McpService;
import com.android.bluetooth.mcp.McpService;
import com.android.bluetooth.vc.VolumeControlService;
import com.android.bluetooth.vc.VolumeControlService;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting;
import com.android.modules.utils.SynchronousResultReceiver;
import com.android.modules.utils.SynchronousResultReceiver;


@@ -110,9 +111,10 @@ public class LeAudioService extends ProfileService {
    private AdapterService mAdapterService;
    private AdapterService mAdapterService;
    private DatabaseManager mDatabaseManager;
    private DatabaseManager mDatabaseManager;
    private HandlerThread mStateMachinesThread;
    private HandlerThread mStateMachinesThread;
    private BluetoothDevice mActiveAudioOutDevice;
    private volatile BluetoothDevice mActiveAudioOutDevice;
    private BluetoothDevice mActiveAudioInDevice;
    private volatile BluetoothDevice mActiveAudioInDevice;
    private LeAudioCodecConfig mLeAudioCodecConfig;
    private LeAudioCodecConfig mLeAudioCodecConfig;
    private Object mGroupLock = new Object();
    ServiceFactory mServiceFactory = new ServiceFactory();
    ServiceFactory mServiceFactory = new ServiceFactory();


    LeAudioNativeInterface mLeAudioNativeInterface;
    LeAudioNativeInterface mLeAudioNativeInterface;
@@ -143,9 +145,11 @@ public class LeAudioService extends ProfileService {
    List<BluetoothLeAudioCodecConfig> mInputLocalCodecCapabilities = new ArrayList<>();
    List<BluetoothLeAudioCodecConfig> mInputLocalCodecCapabilities = new ArrayList<>();
    List<BluetoothLeAudioCodecConfig> mOutputLocalCodecCapabilities = new ArrayList<>();
    List<BluetoothLeAudioCodecConfig> mOutputLocalCodecCapabilities = new ArrayList<>();


    @GuardedBy("mGroupLock")
    private final Map<Integer, LeAudioGroupDescriptor> mGroupDescriptors = new LinkedHashMap<>();
    private final Map<Integer, LeAudioGroupDescriptor> mGroupDescriptors = new LinkedHashMap<>();
    private final Map<BluetoothDevice, LeAudioStateMachine> mStateMachines = new LinkedHashMap<>();
    private final Map<BluetoothDevice, LeAudioStateMachine> mStateMachines = new LinkedHashMap<>();


    @GuardedBy("mGroupLock")
    private final Map<BluetoothDevice, Integer> mDeviceGroupIdMap = new ConcurrentHashMap<>();
    private final Map<BluetoothDevice, Integer> mDeviceGroupIdMap = new ConcurrentHashMap<>();
    private final Map<BluetoothDevice, Integer> mDeviceAudioLocationMap = new ConcurrentHashMap<>();
    private final Map<BluetoothDevice, Integer> mDeviceAudioLocationMap = new ConcurrentHashMap<>();


@@ -210,13 +214,15 @@ public class LeAudioService extends ProfileService {
        mStateMachinesThread = new HandlerThread("LeAudioService.StateMachines");
        mStateMachinesThread = new HandlerThread("LeAudioService.StateMachines");
        mStateMachinesThread.start();
        mStateMachinesThread.start();


        mDeviceGroupIdMap.clear();
        mDeviceAudioLocationMap.clear();
        mDeviceAudioLocationMap.clear();
        mBroadcastStateMap.clear();
        mBroadcastStateMap.clear();
        mBroadcastMetadataList.clear();
        mBroadcastMetadataList.clear();
        mBroadcastsPlaybackMap.clear();
        mBroadcastsPlaybackMap.clear();


        synchronized (mGroupLock) {
            mDeviceGroupIdMap.clear();
            mGroupDescriptors.clear();
            mGroupDescriptors.clear();
        }


        // Setup broadcast receivers
        // Setup broadcast receivers
        IntentFilter filter = new IntentFilter();
        IntentFilter filter = new IntentFilter();
@@ -247,12 +253,19 @@ public class LeAudioService extends ProfileService {


        // Delay the call to init by posting it. This ensures TBS and MCS are fully initialized
        // Delay the call to init by posting it. This ensures TBS and MCS are fully initialized
        // before we start accepting connections
        // before we start accepting connections
        mHandler.post(() ->
        mHandler.post(this::init);
                mLeAudioNativeInterface.init(mLeAudioCodecConfig.getCodecConfigOffloading()));


        return true;
        return true;
    }
    }


    private void init() {
        LeAudioNativeInterface nativeInterface = mLeAudioNativeInterface;
        if (nativeInterface == null) {
            Log.w(TAG, "the service is stopped. ignore init()");
        }
        nativeInterface.init(mLeAudioCodecConfig.getCodecConfigOffloading());
    }

    @Override
    @Override
    protected boolean stop() {
    protected boolean stop() {
        Log.i(TAG, "stop()");
        Log.i(TAG, "stop()");
@@ -264,6 +277,7 @@ public class LeAudioService extends ProfileService {
        setActiveDevice(null);
        setActiveDevice(null);
        //Don't wait for async call with INACTIVE group status, clean active
        //Don't wait for async call with INACTIVE group status, clean active
        //device for active group.
        //device for active group.
        synchronized (mGroupLock) {
            for (Map.Entry<Integer, LeAudioGroupDescriptor> entry : mGroupDescriptors.entrySet()) {
            for (Map.Entry<Integer, LeAudioGroupDescriptor> entry : mGroupDescriptors.entrySet()) {
                LeAudioGroupDescriptor descriptor = entry.getValue();
                LeAudioGroupDescriptor descriptor = entry.getValue();
                Integer group_id = entry.getKey();
                Integer group_id = entry.getKey();
@@ -274,6 +288,9 @@ public class LeAudioService extends ProfileService {
                    break;
                    break;
                }
                }
            }
            }
            mDeviceGroupIdMap.clear();
            mGroupDescriptors.clear();
        }


        // Cleanup native interfaces
        // Cleanup native interfaces
        mLeAudioNativeInterface.cleanup();
        mLeAudioNativeInterface.cleanup();
@@ -297,9 +314,7 @@ public class LeAudioService extends ProfileService {
            mStateMachines.clear();
            mStateMachines.clear();
        }
        }


        mDeviceGroupIdMap.clear();
        mDeviceAudioLocationMap.clear();
        mDeviceAudioLocationMap.clear();
        mGroupDescriptors.clear();


        if (mBroadcastCallbacks != null) {
        if (mBroadcastCallbacks != null) {
            mBroadcastCallbacks.kill();
            mBroadcastCallbacks.kill();
@@ -328,7 +343,6 @@ public class LeAudioService extends ProfileService {
            }
            }
        }
        }


        mAudioManager = null;
        mAdapterService = null;
        mAdapterService = null;
        mAudioManager = null;
        mAudioManager = null;


@@ -423,7 +437,7 @@ public class LeAudioService extends ProfileService {
        }
        }
    }
    }


    public BluetoothDevice getConnectedGroupLeadDevice(int groupId) {
    BluetoothDevice getConnectedGroupLeadDevice(int groupId) {
        return getFirstDeviceFromGroup(groupId);
        return getFirstDeviceFromGroup(groupId);
    }
    }


@@ -499,7 +513,7 @@ public class LeAudioService extends ProfileService {
     * @param device the active device
     * @param device the active device
     * @return true on success, otherwise false
     * @return true on success, otherwise false
     */
     */
    public boolean groupAddNode(int groupId, BluetoothDevice device) {
    boolean groupAddNode(int groupId, BluetoothDevice device) {
        return mLeAudioNativeInterface.groupAddNode(groupId, device);
        return mLeAudioNativeInterface.groupAddNode(groupId, device);
    }
    }


@@ -509,7 +523,7 @@ public class LeAudioService extends ProfileService {
     * @param device the active device
     * @param device the active device
     * @return true on success, otherwise false
     * @return true on success, otherwise false
     */
     */
    public boolean groupRemoveNode(int groupId, BluetoothDevice device) {
    boolean groupRemoveNode(int groupId, BluetoothDevice device) {
        return mLeAudioNativeInterface.groupRemoveNode(groupId, device);
        return mLeAudioNativeInterface.groupRemoveNode(groupId, device);
    }
    }


@@ -519,23 +533,25 @@ public class LeAudioService extends ProfileService {
     * @return true given group exists, otherwise false
     * @return true given group exists, otherwise false
     */
     */
    public boolean isValidDeviceGroup(int group_id) {
    public boolean isValidDeviceGroup(int group_id) {
        return (group_id != LE_AUDIO_GROUP_ID_INVALID) ?
        return group_id != LE_AUDIO_GROUP_ID_INVALID && mDeviceGroupIdMap.containsValue(group_id);
                mDeviceGroupIdMap.containsValue(group_id) :
                false;
    }
    }


    /**
    /**
     * Get all the devices within a given group.
     * Get all the devices within a given group.
     * @param group_id group Id to verify
     * @param groupId group id to get devices
     * @return all devices within a given group or empty list
     * @return all devices within a given group or empty list
     */
     */
    public List<BluetoothDevice> getGroupDevices(int group_id) {
    public List<BluetoothDevice> getGroupDevices(int groupId) {
        List<BluetoothDevice> result = new ArrayList<>();
        List<BluetoothDevice> result = new ArrayList<>();


        if (group_id != LE_AUDIO_GROUP_ID_INVALID) {
        if (groupId == LE_AUDIO_GROUP_ID_INVALID) {
            for (BluetoothDevice storedDevice : mDeviceGroupIdMap.keySet()) {
            return result;
                if (getGroupId(storedDevice) == group_id) {
        }
                    result.add(storedDevice);

        synchronized (mGroupLock) {
            for (Map.Entry<BluetoothDevice, Integer> entry : mDeviceGroupIdMap.entrySet()) {
                if (entry.getValue() == groupId) {
                    result.add(entry.getKey());
                }
                }
            }
            }
        }
        }
@@ -545,11 +561,11 @@ public class LeAudioService extends ProfileService {
    /**
    /**
     * Get supported group audio direction from available context.
     * Get supported group audio direction from available context.
     *
     *
     * @param activeContext bitset of active context to be matched with possible audio direction
     * @param activeContexts bitset of active context to be matched with possible audio direction
     * support.
     * support.
     * @return matched possible audio direction support masked bitset
     * @return matched possible audio direction support masked bitset
     * {@link AUDIO_DIRECTION_INPUT_BIT} if input audio is supported
     * {@link #AUDIO_DIRECTION_INPUT_BIT} if input audio is supported
     * {@link AUDIO_DIRECTION_OUTPUT_BIT} if output audio is supported
     * {@link #AUDIO_DIRECTION_OUTPUT_BIT} if output audio is supported
     */
     */
    private Integer getAudioDirectionsFromActiveContextsMap(Integer activeContexts) {
    private Integer getAudioDirectionsFromActiveContextsMap(Integer activeContexts) {
        Integer supportedAudioDirections = 0;
        Integer supportedAudioDirections = 0;
@@ -565,12 +581,14 @@ public class LeAudioService extends ProfileService {
    }
    }


    private Integer getActiveGroupId() {
    private Integer getActiveGroupId() {
        synchronized (mGroupLock) {
            for (Map.Entry<Integer, LeAudioGroupDescriptor> entry : mGroupDescriptors.entrySet()) {
            for (Map.Entry<Integer, LeAudioGroupDescriptor> entry : mGroupDescriptors.entrySet()) {
                LeAudioGroupDescriptor descriptor = entry.getValue();
                LeAudioGroupDescriptor descriptor = entry.getValue();
                if (descriptor.mIsActive) {
                if (descriptor.mIsActive) {
                    return entry.getKey();
                    return entry.getKey();
                }
                }
            }
            }
        }
        return LE_AUDIO_GROUP_ID_INVALID;
        return LE_AUDIO_GROUP_ID_INVALID;
    }
    }


@@ -669,21 +687,21 @@ public class LeAudioService extends ProfileService {
    }
    }


    private BluetoothDevice getFirstDeviceFromGroup(Integer groupId) {
    private BluetoothDevice getFirstDeviceFromGroup(Integer groupId) {
        if (groupId != LE_AUDIO_GROUP_ID_INVALID) {
        if (groupId == LE_AUDIO_GROUP_ID_INVALID) {
            return null;
        }
        synchronized (mGroupLock) {
            for (Map.Entry<BluetoothDevice, Integer> entry : mDeviceGroupIdMap.entrySet()) {
            for (Map.Entry<BluetoothDevice, Integer> entry : mDeviceGroupIdMap.entrySet()) {
                if (entry.getValue() != groupId) {
                if (entry.getValue() != groupId) {
                    continue;
                    continue;
                }
                }

                LeAudioStateMachine sm = mStateMachines.get(entry.getKey());
                LeAudioStateMachine sm = mStateMachines.get(entry.getKey());
                if (sm == null || sm.getConnectionState() != BluetoothProfile.STATE_CONNECTED) {
                if (sm == null || sm.getConnectionState() != BluetoothProfile.STATE_CONNECTED) {
                    continue;
                    continue;
                }
                }

                return entry.getKey();
                return entry.getKey();
            }
            }
        }
        }

        return null;
        return null;
    }
    }


@@ -720,10 +738,12 @@ public class LeAudioService extends ProfileService {
                }
                }
            } else if (previousGroupId != LE_AUDIO_GROUP_ID_INVALID) {
            } else if (previousGroupId != LE_AUDIO_GROUP_ID_INVALID) {
                /* Mark old group as no active */
                /* Mark old group as no active */
                LeAudioGroupDescriptor descriptor = mGroupDescriptors.get(previousGroupId);
                LeAudioGroupDescriptor descriptor = getGroupDescriptor(previousGroupId);
                if (descriptor != null) {
                    descriptor.mIsActive = false;
                    descriptor.mIsActive = false;
                }
                }
            }
            }
        }


        BluetoothDevice previousInDevice = mActiveAudioInDevice;
        BluetoothDevice previousInDevice = mActiveAudioInDevice;


@@ -784,10 +804,12 @@ public class LeAudioService extends ProfileService {
            } else if (previousGroupId != LE_AUDIO_GROUP_ID_INVALID) {
            } else if (previousGroupId != LE_AUDIO_GROUP_ID_INVALID) {
                Log.i(TAG, " Switching active group from " + previousGroupId + " to " + groupId);
                Log.i(TAG, " Switching active group from " + previousGroupId + " to " + groupId);
                /* Mark old group as no active */
                /* Mark old group as no active */
                LeAudioGroupDescriptor descriptor = mGroupDescriptors.get(previousGroupId);
                LeAudioGroupDescriptor descriptor = getGroupDescriptor(previousGroupId);
                if (descriptor != null) {
                    descriptor.mIsActive = false;
                    descriptor.mIsActive = false;
                }
                }
            }
            }
        }


        BluetoothDevice previousOutDevice = mActiveAudioOutDevice;
        BluetoothDevice previousOutDevice = mActiveAudioOutDevice;


@@ -851,9 +873,8 @@ public class LeAudioService extends ProfileService {


    /**
    /**
     * Set the active device group.
     * Set the active device group.
     * @param groupId group Id to set active
     */
     */
    private void setActiveDeviceGroup(BluetoothDevice device) {
    private void setActiveGroupWithDevice(BluetoothDevice device) {
        int groupId = LE_AUDIO_GROUP_ID_INVALID;
        int groupId = LE_AUDIO_GROUP_ID_INVALID;


        if (device != null) {
        if (device != null) {
@@ -862,9 +883,9 @@ public class LeAudioService extends ProfileService {


        int currentlyActiveGroupId = getActiveGroupId();
        int currentlyActiveGroupId = getActiveGroupId();
        if (DBG) {
        if (DBG) {
            Log.d(TAG, "setActiveDeviceGroup = " + groupId +
            Log.d(TAG, "setActiveGroupWithDevice = " + groupId
                       ", currentlyActiveGroupId = " + currentlyActiveGroupId +
                    + ", currentlyActiveGroupId = " + currentlyActiveGroupId
                       ", device: " + device);
                    + ", device: " + device);
        }
        }


        if (groupId == currentlyActiveGroupId) {
        if (groupId == currentlyActiveGroupId) {
@@ -882,24 +903,22 @@ public class LeAudioService extends ProfileService {
     * @return true on success, otherwise false
     * @return true on success, otherwise false
     */
     */
    public boolean setActiveDevice(BluetoothDevice device) {
    public boolean setActiveDevice(BluetoothDevice device) {
        synchronized (mStateMachines) {
        /* Clear active group */
        /* Clear active group */
        if (device == null) {
        if (device == null) {
                setActiveDeviceGroup(device);
            setActiveGroupWithDevice(device);
            return true;
            return true;
        }
        }
        if (getConnectionState(device) != BluetoothProfile.STATE_CONNECTED) {
        if (getConnectionState(device) != BluetoothProfile.STATE_CONNECTED) {
                Log.e(TAG, "setActiveDevice(" + device + "): failed because group device is not " +
            Log.e(TAG, "setActiveDevice(" + device + "): failed because group device is not "
                        "connected");
                    + "connected");
            return false;
            return false;
        }
        }
            setActiveDeviceGroup(device);
        setActiveGroupWithDevice(device);
        return true;
        return true;
    }
    }
    }


    /**
    /**
     * Get the active LE audio device.
     * Get the active LE audio devices.
     *
     *
     * Note: When LE audio group is active, one of the Bluetooth device address
     * Note: When LE audio group is active, one of the Bluetooth device address
     * which belongs to the group, represents the active LE audio group.
     * which belongs to the group, represents the active LE audio group.
@@ -912,17 +931,16 @@ public class LeAudioService extends ProfileService {
        if (DBG) {
        if (DBG) {
            Log.d(TAG, "getActiveDevices");
            Log.d(TAG, "getActiveDevices");
        }
        }
        ArrayList<BluetoothDevice> activeDevices = new ArrayList<>();
        ArrayList<BluetoothDevice> activeDevices = new ArrayList<>(2);
        activeDevices.add(null);
        activeDevices.add(null);
        activeDevices.add(null);
        activeDevices.add(null);
        synchronized (mStateMachines) {

        int currentlyActiveGroupId = getActiveGroupId();
        int currentlyActiveGroupId = getActiveGroupId();
        if (currentlyActiveGroupId == LE_AUDIO_GROUP_ID_INVALID) {
        if (currentlyActiveGroupId == LE_AUDIO_GROUP_ID_INVALID) {
            return activeDevices;
            return activeDevices;
        }
        }
                activeDevices.add(0, mActiveAudioOutDevice);
        activeDevices.set(0, mActiveAudioOutDevice);
                activeDevices.add(1, mActiveAudioInDevice);
        activeDevices.set(1, mActiveAudioInDevice);
        }
        return activeDevices;
        return activeDevices;
    }
    }


@@ -959,7 +977,6 @@ public class LeAudioService extends ProfileService {
                 sm.sendMessage(LeAudioStateMachine.CONNECT);
                 sm.sendMessage(LeAudioStateMachine.CONNECT);
            }
            }
        }
        }

    }
    }


    // Suppressed since this is part of a local process
    // Suppressed since this is part of a local process
@@ -995,27 +1012,18 @@ public class LeAudioService extends ProfileService {
                return;
                return;
            }
            }
        } else if (stackEvent.type == LeAudioStackEvent.EVENT_TYPE_GROUP_NODE_STATUS_CHANGED) {
        } else if (stackEvent.type == LeAudioStackEvent.EVENT_TYPE_GROUP_NODE_STATUS_CHANGED) {
            int group_id = stackEvent.valueInt1;
            int groupId = stackEvent.valueInt1;
            int node_status = stackEvent.valueInt2;
            int nodeStatus = stackEvent.valueInt2;


            Objects.requireNonNull(stackEvent.device,
            Objects.requireNonNull(stackEvent.device,
                    "Device should never be null, event: " + stackEvent);
                    "Device should never be null, event: " + stackEvent);


            switch (node_status) {
            switch (nodeStatus) {
                case LeAudioStackEvent.GROUP_NODE_ADDED:
                case LeAudioStackEvent.GROUP_NODE_ADDED:
                    mDeviceGroupIdMap.put(device, group_id);
                    handleGroupNodeAdded(device, groupId);
                    LeAudioGroupDescriptor descriptor = mGroupDescriptors.get(group_id);
                    if (descriptor == null) {
                        mGroupDescriptors.put(group_id, new LeAudioGroupDescriptor());
                    }
                    notifyGroupNodeAdded(device, group_id);
                    break;
                    break;
                case LeAudioStackEvent.GROUP_NODE_REMOVED:
                case LeAudioStackEvent.GROUP_NODE_REMOVED:
                    mDeviceGroupIdMap.remove(device);
                    handleGroupNodeRemoved(device, groupId);
                    if (mDeviceGroupIdMap.containsValue(group_id) == false) {
                        mGroupDescriptors.remove(group_id);
                    }
                    notifyGroupNodeRemoved(device, group_id);
                    break;
                    break;
                default:
                default:
                    break;
                    break;
@@ -1027,7 +1035,7 @@ public class LeAudioService extends ProfileService {
        } else if (stackEvent.type
        } else if (stackEvent.type
                        == LeAudioStackEvent.EVENT_TYPE_AUDIO_GROUP_CODEC_CONFIG_CHANGED) {
                        == LeAudioStackEvent.EVENT_TYPE_AUDIO_GROUP_CODEC_CONFIG_CHANGED) {
            int groupId = stackEvent.valueInt1;
            int groupId = stackEvent.valueInt1;
            LeAudioGroupDescriptor descriptor = mGroupDescriptors.get(groupId);
            LeAudioGroupDescriptor descriptor = getGroupDescriptor(groupId);
            if (descriptor == null) {
            if (descriptor == null) {
                Log.e(TAG, " Group not found " + groupId);
                Log.e(TAG, " Group not found " + groupId);
                return;
                return;
@@ -1050,27 +1058,26 @@ public class LeAudioService extends ProfileService {


            descriptor.mCodecStatus = status;
            descriptor.mCodecStatus = status;
            notifyUnicastCodecConfigChanged(groupId, status);
            notifyUnicastCodecConfigChanged(groupId, status);

        } else if (stackEvent.type == LeAudioStackEvent.EVENT_TYPE_AUDIO_CONF_CHANGED) {
        } else if (stackEvent.type == LeAudioStackEvent.EVENT_TYPE_AUDIO_CONF_CHANGED) {
            int direction = stackEvent.valueInt1;
            int direction = stackEvent.valueInt1;
            int group_id = stackEvent.valueInt2;
            int groupId = stackEvent.valueInt2;
            int snk_audio_location = stackEvent.valueInt3;
            int snk_audio_location = stackEvent.valueInt3;
            int src_audio_location = stackEvent.valueInt4;
            int src_audio_location = stackEvent.valueInt4;
            int available_contexts = stackEvent.valueInt5;
            int available_contexts = stackEvent.valueInt5;


            LeAudioGroupDescriptor descriptor = mGroupDescriptors.get(group_id);
            LeAudioGroupDescriptor descriptor = getGroupDescriptor(groupId);
            if (descriptor != null) {
            if (descriptor != null) {
                if (descriptor.mIsActive) {
                if (descriptor.mIsActive) {
                    descriptor.mIsActive =
                    descriptor.mIsActive =
                        updateActiveDevices(group_id, descriptor.mActiveContexts,
                        updateActiveDevices(groupId, descriptor.mActiveContexts,
                                        available_contexts, descriptor.mIsActive);
                                        available_contexts, descriptor.mIsActive);
                    if (!descriptor.mIsActive) {
                    if (!descriptor.mIsActive) {
                        notifyGroupStatusChanged(group_id, BluetoothLeAudio.GROUP_STATUS_INACTIVE);
                        notifyGroupStatusChanged(groupId, BluetoothLeAudio.GROUP_STATUS_INACTIVE);
                    }
                    }
                }
                }
                descriptor.mActiveContexts = available_contexts;
                descriptor.mActiveContexts = available_contexts;
            } else {
            } else {
                Log.e(TAG, "no descriptors for group: " + group_id);
                Log.e(TAG, "no descriptors for group: " + groupId);
            }
            }
        } else if (stackEvent.type == LeAudioStackEvent.EVENT_TYPE_SINK_AUDIO_LOCATION_AVAILABLE) {
        } else if (stackEvent.type == LeAudioStackEvent.EVENT_TYPE_SINK_AUDIO_LOCATION_AVAILABLE) {
            Objects.requireNonNull(stackEvent.device,
            Objects.requireNonNull(stackEvent.device,
@@ -1084,36 +1091,36 @@ public class LeAudioService extends ProfileService {
                        + " audio location:" + sink_audio_location);
                        + " audio location:" + sink_audio_location);
            }
            }
        } else if (stackEvent.type == LeAudioStackEvent.EVENT_TYPE_GROUP_STATUS_CHANGED) {
        } else if (stackEvent.type == LeAudioStackEvent.EVENT_TYPE_GROUP_STATUS_CHANGED) {
            int group_id = stackEvent.valueInt1;
            int groupId = stackEvent.valueInt1;
            int group_status = stackEvent.valueInt2;
            int groupStatus = stackEvent.valueInt2;
            boolean notifyGroupStatus = false;
            boolean notifyGroupStatus = false;


            switch (group_status) {
            switch (groupStatus) {
                case LeAudioStackEvent.GROUP_STATUS_ACTIVE: {
                case LeAudioStackEvent.GROUP_STATUS_ACTIVE: {
                    LeAudioGroupDescriptor descriptor = mGroupDescriptors.get(group_id);
                    LeAudioGroupDescriptor descriptor = getGroupDescriptor(groupId);
                    if (descriptor != null) {
                    if (descriptor != null) {
                        if (!descriptor.mIsActive) {
                        if (!descriptor.mIsActive) {
                            descriptor.mIsActive = updateActiveDevices(group_id,
                            descriptor.mIsActive = updateActiveDevices(groupId,
                                                ACTIVE_CONTEXTS_NONE,
                                                ACTIVE_CONTEXTS_NONE,
                                                descriptor.mActiveContexts, true);
                                                descriptor.mActiveContexts, true);
                            notifyGroupStatus = descriptor.mIsActive;
                            notifyGroupStatus = descriptor.mIsActive;
                        }
                        }
                    } else {
                    } else {
                        Log.e(TAG, "no descriptors for group: " + group_id);
                        Log.e(TAG, "no descriptors for group: " + groupId);
                    }
                    }
                    break;
                    break;
                }
                }
                case LeAudioStackEvent.GROUP_STATUS_INACTIVE: {
                case LeAudioStackEvent.GROUP_STATUS_INACTIVE: {
                    LeAudioGroupDescriptor descriptor = mGroupDescriptors.get(group_id);
                    LeAudioGroupDescriptor descriptor = getGroupDescriptor(groupId);
                    if (descriptor != null) {
                    if (descriptor != null) {
                        if (descriptor.mIsActive) {
                        if (descriptor.mIsActive) {
                            descriptor.mIsActive = false;
                            descriptor.mIsActive = false;
                            updateActiveDevices(group_id, descriptor.mActiveContexts,
                            updateActiveDevices(groupId, descriptor.mActiveContexts,
                                    ACTIVE_CONTEXTS_NONE, descriptor.mIsActive);
                                    ACTIVE_CONTEXTS_NONE, descriptor.mIsActive);
                            notifyGroupStatus = true;
                            notifyGroupStatus = true;
                        }
                        }
                    } else {
                    } else {
                        Log.e(TAG, "no descriptors for group: " + group_id);
                        Log.e(TAG, "no descriptors for group: " + groupId);
                    }
                    }
                    break;
                    break;
                }
                }
@@ -1122,7 +1129,7 @@ public class LeAudioService extends ProfileService {
            }
            }


            if (notifyGroupStatus) {
            if (notifyGroupStatus) {
                notifyGroupStatusChanged(group_id, group_status);
                notifyGroupStatusChanged(groupId, groupStatus);
            }
            }


        } else if (stackEvent.type == LeAudioStackEvent.EVENT_TYPE_BROADCAST_CREATED) {
        } else if (stackEvent.type == LeAudioStackEvent.EVENT_TYPE_BROADCAST_CREATED) {
@@ -1340,7 +1347,7 @@ public class LeAudioService extends ProfileService {
                //         BluetoothMetricsProto.ProfileId.LE_AUDIO);
                //         BluetoothMetricsProto.ProfileId.LE_AUDIO);
            }
            }


            LeAudioGroupDescriptor descriptor = mGroupDescriptors.get(myGroupId);
            LeAudioGroupDescriptor descriptor = getGroupDescriptor(myGroupId);
            if (descriptor != null) {
            if (descriptor != null) {
                descriptor.mIsConnected = true;
                descriptor.mIsConnected = true;
                /* HearingAid activates device after connection
                /* HearingAid activates device after connection
@@ -1372,7 +1379,7 @@ public class LeAudioService extends ProfileService {
            }
            }


            int myGroupId = getGroupId(device);
            int myGroupId = getGroupId(device);
            LeAudioGroupDescriptor descriptor = mGroupDescriptors.get(myGroupId);
            LeAudioGroupDescriptor descriptor = getGroupDescriptor(myGroupId);
            if (descriptor == null) {
            if (descriptor == null) {
                Log.e(TAG, "no descriptors for group: " + myGroupId);
                Log.e(TAG, "no descriptors for group: " + myGroupId);
                return;
                return;
@@ -1520,8 +1527,10 @@ public class LeAudioService extends ProfileService {
        if (device == null) {
        if (device == null) {
            return LE_AUDIO_GROUP_ID_INVALID;
            return LE_AUDIO_GROUP_ID_INVALID;
        }
        }
        synchronized (mGroupLock) {
            return mDeviceGroupIdMap.getOrDefault(device, LE_AUDIO_GROUP_ID_INVALID);
            return mDeviceGroupIdMap.getOrDefault(device, LE_AUDIO_GROUP_ID_INVALID);
        }
        }
    }


    /**
    /**
     * Set volume for streaming devices
     * Set volume for streaming devices
@@ -1544,6 +1553,23 @@ public class LeAudioService extends ProfileService {
        }
        }
    }
    }


    private LeAudioGroupDescriptor getGroupDescriptor(int groupId) {
        synchronized (mGroupLock) {
            return mGroupDescriptors.get(groupId);
        }
    }

    private void handleGroupNodeAdded(BluetoothDevice device, int groupId) {
        synchronized (mGroupLock) {
            mDeviceGroupIdMap.put(device, groupId);
            LeAudioGroupDescriptor descriptor = mGroupDescriptors.get(groupId);
            if (descriptor == null) {
                mGroupDescriptors.put(groupId, new LeAudioGroupDescriptor());
            }
            notifyGroupNodeAdded(device, groupId);
        }
    }

    private void notifyGroupNodeAdded(BluetoothDevice device, int groupId) {
    private void notifyGroupNodeAdded(BluetoothDevice device, int groupId) {
        if (mLeAudioCallbacks != null) {
        if (mLeAudioCallbacks != null) {
            int n = mLeAudioCallbacks.beginBroadcast();
            int n = mLeAudioCallbacks.beginBroadcast();
@@ -1558,6 +1584,16 @@ public class LeAudioService extends ProfileService {
        }
        }
    }
    }


    private void handleGroupNodeRemoved(BluetoothDevice device, int groupId) {
        synchronized (mGroupLock) {
            mDeviceGroupIdMap.remove(device);
            if (!mDeviceGroupIdMap.containsValue(groupId)) {
                mGroupDescriptors.remove(groupId);
            }
            notifyGroupNodeRemoved(device, groupId);
        }
    }

    private void notifyGroupNodeRemoved(BluetoothDevice device, int groupId) {
    private void notifyGroupNodeRemoved(BluetoothDevice device, int groupId) {
        if (mLeAudioCallbacks != null) {
        if (mLeAudioCallbacks != null) {
            int n = mLeAudioCallbacks.beginBroadcast();
            int n = mLeAudioCallbacks.beginBroadcast();
@@ -1741,7 +1777,7 @@ public class LeAudioService extends ProfileService {
        if (DBG) {
        if (DBG) {
            Log.d(TAG, "getCodecStatus(" + groupId + ")");
            Log.d(TAG, "getCodecStatus(" + groupId + ")");
        }
        }
        LeAudioGroupDescriptor descriptor = mGroupDescriptors.get(groupId);
        LeAudioGroupDescriptor descriptor = getGroupDescriptor(groupId);
        if (descriptor != null) {
        if (descriptor != null) {
            return descriptor.mCodecStatus;
            return descriptor.mCodecStatus;
        }
        }
@@ -1764,7 +1800,7 @@ public class LeAudioService extends ProfileService {
                    + Objects.toString(inputCodecConfig)
                    + Objects.toString(inputCodecConfig)
                    + Objects.toString(outputCodecConfig));
                    + Objects.toString(outputCodecConfig));
        }
        }
        LeAudioGroupDescriptor descriptor = mGroupDescriptors.get(groupId);
        LeAudioGroupDescriptor descriptor = getGroupDescriptor(groupId);
        if (descriptor == null) {
        if (descriptor == null) {
            Log.e(TAG, "setCodecConfigPreference: Invalid groupId, " + groupId);
            Log.e(TAG, "setCodecConfigPreference: Invalid groupId, " + groupId);
            return;
            return;
@@ -1793,7 +1829,6 @@ public class LeAudioService extends ProfileService {
                                inputCodecConfig, outputCodecConfig);
                                inputCodecConfig, outputCodecConfig);
    }
    }



    /**
    /**
     * Binder object: must be a static class or memory leak may occur
     * Binder object: must be a static class or memory leak may occur
     */
     */