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

Commit a9c10d17 authored by Rongxuan Liu's avatar Rongxuan Liu Committed by Automerger Merge Worker
Browse files

Merge "[le audio] Switch active device group during broadcast" into main am:...

Merge "[le audio] Switch active device group during broadcast" into main am: 01f60591 am: e3f987d3

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



Change-Id: Ie555fa6ad1e1768c84cf2555d8a2236ce1bc5674
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents f2999a4e e3f987d3
Loading
Loading
Loading
Loading
+57 −7
Original line number Diff line number Diff line
@@ -24,9 +24,9 @@ import static com.android.bluetooth.flags.Flags.leaudioBroadcastFeatureSupport;
import static com.android.bluetooth.Utils.enforceBluetoothPrivilegedPermission;
import static com.android.modules.utils.build.SdkLevel.isAtLeastU;


import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothLeAudio;
@@ -56,6 +56,7 @@ import android.media.AudioDeviceCallback;
import android.media.AudioDeviceInfo;
import android.media.AudioManager;
import android.media.BluetoothProfileConnectionInfo;
import android.os.Binder;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
@@ -63,6 +64,8 @@ import android.os.Parcel;
import android.os.ParcelUuid;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
import android.sysprop.BluetoothProperties;
import android.util.Log;
import android.util.Pair;
@@ -127,6 +130,13 @@ public class LeAudioService extends ProfileService {
     */
    private static final int AUDIO_DIRECTION_INPUT_BIT = 0x02;

    /**
     * This is used by application read-only for checking the fallback active group id.
     *
     */
    public static final String BLUETOOTH_LE_BROADCAST_FALLBACK_ACTIVE_GROUP_ID =
            "bluetooth_le_broadcast_fallback_active_group_id";

    private AdapterService mAdapterService;
    private DatabaseManager mDatabaseManager;
    private HandlerThread mStateMachinesThread;
@@ -1756,6 +1766,16 @@ public class LeAudioService extends ProfileService {
                            + mExposedActiveDevice);
        }

        if (isBroadcastActive()
                && currentlyActiveGroupId == LE_AUDIO_GROUP_ID_INVALID
                && mUnicastGroupIdDeactivatedForBroadcastTransition != LE_AUDIO_GROUP_ID_INVALID
                && groupId != LE_AUDIO_GROUP_ID_INVALID) {
            // If broadcast is ongoing and need to update unicast fallback active group
            // we need to update the cached group id and skip changing the active device
            updateFallbackUnicastGroupIdForBroadcast(groupId);
            return;
        }

        LeAudioGroupDescriptor groupDescriptor = getGroupDescriptor(currentlyActiveGroupId);
        if (groupDescriptor != null && groupId == currentlyActiveGroupId) {
            /* Make sure active group is already exposed to audio framework.
@@ -2345,7 +2365,7 @@ public class LeAudioService extends ProfileService {
        if (unicastDevice == null) {
            Log.e(TAG, "EVENT_TYPE_BROADCAST_DESTROYED: No valid unicast device for group ID: "
                    + mUnicastGroupIdDeactivatedForBroadcastTransition);
            mUnicastGroupIdDeactivatedForBroadcastTransition = LE_AUDIO_GROUP_ID_INVALID;
            updateFallbackUnicastGroupIdForBroadcast(LE_AUDIO_GROUP_ID_INVALID);
            return;
        }

@@ -2356,8 +2376,7 @@ public class LeAudioService extends ProfileService {
                    + unicastDevice);
        }

        mUnicastGroupIdDeactivatedForBroadcastTransition = LE_AUDIO_GROUP_ID_INVALID;

        updateFallbackUnicastGroupIdForBroadcast(LE_AUDIO_GROUP_ID_INVALID);
        setActiveDevice(unicastDevice);
    }

@@ -2575,14 +2594,14 @@ public class LeAudioService extends ProfileService {

                    /* Check if broadcast was deactivated due to unicast */
                    if (mBroadcastIdDeactivatedForUnicastTransition.isPresent()) {
                        mUnicastGroupIdDeactivatedForBroadcastTransition = groupId;
                        updateFallbackUnicastGroupIdForBroadcast(groupId);
                        mQueuedInCallValue = Optional.empty();
                        startBroadcast(mBroadcastIdDeactivatedForUnicastTransition.get());
                        mBroadcastIdDeactivatedForUnicastTransition = Optional.empty();
                    }

                    if (!mCreateBroadcastQueue.isEmpty()) {
                        mUnicastGroupIdDeactivatedForBroadcastTransition = groupId;
                        updateFallbackUnicastGroupIdForBroadcast(groupId);
                        BluetoothLeBroadcastSettings settings = mCreateBroadcastQueue.remove();
                        createBroadcast(settings);
                    }
@@ -3471,7 +3490,7 @@ public class LeAudioService extends ProfileService {
                mGroupDescriptors.remove(groupId);

                if (mUnicastGroupIdDeactivatedForBroadcastTransition == groupId) {
                    mUnicastGroupIdDeactivatedForBroadcastTransition = LE_AUDIO_GROUP_ID_INVALID;
                    updateFallbackUnicastGroupIdForBroadcast(LE_AUDIO_GROUP_ID_INVALID);
                }
            }
            notifyGroupNodeRemoved(device, groupId);
@@ -3651,6 +3670,37 @@ public class LeAudioService extends ProfileService {
        }
    }

    /**
     * Update the fallback unicast group id during the handover to broadcast Also store the fallback
     * group id in Settings store.
     *
     * @param groupId group id to update
     */
    private void updateFallbackUnicastGroupIdForBroadcast(int groupId) {
        Log.i(
                TAG,
                "Update unicast fallback active group from: "
                        + mUnicastGroupIdDeactivatedForBroadcastTransition
                        + " to : "
                        + groupId);
        mUnicastGroupIdDeactivatedForBroadcastTransition = groupId;

        // waive WRITE_SECURE_SETTINGS permission check
        final long callingIdentity = Binder.clearCallingIdentity();
        try {
            Context userContext =
                    getApplicationContext()
                            .createContextAsUser(
                                    UserHandle.of(ActivityManager.getCurrentUser()), 0);
            Settings.Secure.putInt(
                    userContext.getContentResolver(),
                    BLUETOOTH_LE_BROADCAST_FALLBACK_ACTIVE_GROUP_ID,
                    groupId);
        } finally {
            Binder.restoreCallingIdentity(callingIdentity);
        }
    }

    /**
     * Gets the current codec status (configuration and capability).
     *
+43 −0
Original line number Diff line number Diff line
@@ -1370,6 +1370,49 @@ public class LeAudioServiceTest {
        verify(mTbsService, times(0)).clearInbandRingtoneSupport(mSingleDevice);
    }

    /** Test update unicast fallback active group when broadcast is ongoing */
    @Test
    public void testUpdateUnicastFallbackActiveDeviceGroupDuringBroadcast() {
        int groupId = 1;
        int preGroupId = 2;
        /* AUDIO_DIRECTION_OUTPUT_BIT = 0x01 */
        int direction = 1;
        int snkAudioLocation = 3;
        int srcAudioLocation = 4;
        int availableContexts = 5 + BluetoothLeAudio.CONTEXT_TYPE_RINGTONE;

        // Not connected device
        assertThat(mService.setActiveDevice(mSingleDevice)).isFalse();

        // Connected device
        doReturn(true).when(mNativeInterface).connectLeAudio(any(BluetoothDevice.class));
        connectTestDevice(mSingleDevice, testGroupId);

        mService.mUnicastGroupIdDeactivatedForBroadcastTransition = preGroupId;
        // mock create broadcast and currentlyActiveGroupId remains LE_AUDIO_GROUP_ID_INVALID
        LeAudioStackEvent broadcastCreatedEvent =
                new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_BROADCAST_CREATED);
        broadcastCreatedEvent.device = mSingleDevice;
        broadcastCreatedEvent.valueInt1 = 1;
        broadcastCreatedEvent.valueBool1 = true;
        mService.messageFromNative(broadcastCreatedEvent);

        LeAudioStackEvent audioConfChangedEvent =
                new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_AUDIO_CONF_CHANGED);
        audioConfChangedEvent.device = mSingleDevice;
        audioConfChangedEvent.valueInt1 = direction;
        audioConfChangedEvent.valueInt2 = groupId;
        audioConfChangedEvent.valueInt3 = snkAudioLocation;
        audioConfChangedEvent.valueInt4 = srcAudioLocation;
        audioConfChangedEvent.valueInt5 = availableContexts;
        mService.messageFromNative(audioConfChangedEvent);

        // Verify only update the fallback group and not proceed to change active
        assertThat(mService.setActiveDevice(mSingleDevice)).isTrue();
        assertThat(mService.mUnicastGroupIdDeactivatedForBroadcastTransition).isEqualTo(groupId);
        verify(mNativeInterface, times(0)).groupSetActive(anyInt());
    }

    /**
     * Test getting active device
     */