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

Commit 2d4126b0 authored by Rongxuan Liu's avatar Rongxuan Liu Committed by Gerrit Code Review
Browse files

Merge changes I59bfb077,Ia1d5adc5 into main

* changes:
  bass_client: Add intentional and unintentional device disconnection tests
  broadcast: Consider stopping broadcast if no potential receivers
parents b50ef041 b48d431c
Loading
Loading
Loading
Loading
+251 −9
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -85,6 +86,17 @@ public class BassClientService extends ProfileService {
    private static final int STATUS_LOCAL_STREAM_STREAMING = 1;
    private static final int STATUS_LOCAL_STREAM_SUSPENDED = 2;

    // Do not modify without updating the HAL bt_le_audio.h files.
    // Match up with BroadcastState enum of bt_le_audio.h
    private static final int BROADCAST_STATE_STOPPED = 0;
    private static final int BROADCAST_STATE_CONFIGURING = 1;
    private static final int BROADCAST_STATE_PAUSED = 2;
    private static final int BROADCAST_STATE_STOPPING = 3;
    private static final int BROADCAST_STATE_STREAMING = 4;

    /* 1 minute timeout for primary device reconnection in Private Broadcast case */
    private static final int DIALING_OUT_TIMEOUT_MS = 60000;

    private static BassClientService sService;

    private final Map<BluetoothDevice, BassClientStateMachine> mStateMachines = new HashMap<>();
@@ -101,6 +113,8 @@ public class BassClientService extends ProfileService {
            new ConcurrentHashMap<>();
    private final LinkedList<BluetoothDevice> mPausedBroadcastSinks = new LinkedList<>();
    private final Deque<AddSourceData> mPendingAddSources = new ArrayDeque<>();
    private final Map<Integer, HashSet<BluetoothDevice>> mLocalBroadcastReceivers =
            new ConcurrentHashMap<>();

    private HandlerThread mStateMachinesThread;
    private HandlerThread mCallbackHandlerThread;
@@ -108,6 +122,7 @@ public class BassClientService extends ProfileService {
    private AdapterService mAdapterService;
    private DatabaseManager mDatabaseManager;
    private BluetoothAdapter mBluetoothAdapter = null;
    private DialingOutTimeoutEvent mDialingOutTimeoutEvent = null;

    /* Caching the PeriodicAdvertisementResult from Broadcast source */
    /* This is stored at service so that each device state machine can access
@@ -415,6 +430,11 @@ public class BassClientService extends ProfileService {

        mUnicastSourceStreamStatus = Optional.empty();

        if (mDialingOutTimeoutEvent != null) {
            mHandler.removeCallbacks(mDialingOutTimeoutEvent);
            mDialingOutTimeoutEvent = null;
        }

        if (mIsAssistantActive) {
            LeAudioService leAudioService = mServiceFactory.getLeAudioService();
            if (leAudioService != null) {
@@ -455,6 +475,9 @@ public class BassClientService extends ProfileService {
        if (mActiveSourceMap != null) {
            mActiveSourceMap.clear();
        }
        if (mLocalBroadcastReceivers != null) {
            mLocalBroadcastReceivers.clear();
        }
        if (mPendingGroupOp != null) {
            mPendingGroupOp.clear();
        }
@@ -650,6 +673,27 @@ public class BassClientService extends ProfileService {
        }
    }

    private void localNotifySourceAdded(
            BluetoothDevice sink, BluetoothLeBroadcastReceiveState receiveState) {
        if (!isLocalBroadcast(receiveState)) {
            return;
        }

        int broadcastId = receiveState.getBroadcastId();

        /* Track devices bonded to local broadcast for further broadcast status handling when sink
         * device is:
         *     - disconnecting (if no more receivers, broadcast can be stopped)
         *     - connecting (resynchronize if connection lost)
         */
        if (mLocalBroadcastReceivers.containsKey(broadcastId)) {
            mLocalBroadcastReceivers.get(broadcastId).add(sink);
        } else {
            mLocalBroadcastReceivers.put(
                    broadcastId, new HashSet<BluetoothDevice>(Arrays.asList(sink)));
        }
    }

    private void setSourceGroupManaged(BluetoothDevice sink, int sourceId, boolean isGroupOp) {
        log("setSourceGroupManaged device: " + sink);
        if (isGroupOp) {
@@ -829,6 +873,38 @@ public class BassClientService extends ProfileService {
        }
    }

    class DialingOutTimeoutEvent implements Runnable {
        Integer mBroadcastId;

        DialingOutTimeoutEvent(Integer broadcastId) {
            mBroadcastId = broadcastId;
        }

        @Override
        public void run() {
            mDialingOutTimeoutEvent = null;

            if (getBassClientService() == null) {
                Log.e(TAG, "DialingOutTimeoutEvent: No Bass service");
                return;
            }

            LeAudioService leAudioService = mServiceFactory.getLeAudioService();
            if (leAudioService == null) {
                Log.d(TAG, "DialingOutTimeoutEvent: No available LeAudioService");
                return;
            }

            sEventLogger.logd(DBG, TAG, "Broadcast timeout: " + mBroadcastId);
            mLocalBroadcastReceivers.remove(mBroadcastId);
            leAudioService.stopBroadcast(mBroadcastId);
        }

        public boolean isScheduledForBroadcast(Integer broadcastId) {
            return mBroadcastId.equals(broadcastId);
        }
    }

    /**
     * Get the BassClientService instance
     *
@@ -866,6 +942,29 @@ public class BassClientService extends ProfileService {
        mActiveSourceMap.remove(device);
    }

    private void handleReconnectingAudioSharingModeDevice(BluetoothDevice device) {
        /* In case of reconnecting Audio Sharing mode device */
        if (mDialingOutTimeoutEvent != null) {
            for (Map.Entry<Integer, HashSet<BluetoothDevice>> entry :
                    mLocalBroadcastReceivers.entrySet()) {
                Integer broadcastId = entry.getKey();
                HashSet<BluetoothDevice> devices = entry.getValue();

                /* If associated with any broadcast, try to remove pending timeout callback */
                if ((mDialingOutTimeoutEvent.isScheduledForBroadcast(broadcastId))
                        && (devices.contains(device))) {
                    Log.i(
                            TAG,
                            "connectionStateChanged: reconnected previousely synced device: "
                                    + device);
                    mHandler.removeCallbacks(mDialingOutTimeoutEvent);
                    mDialingOutTimeoutEvent = null;
                    break;
                }
            }
        }
    }

    void handleConnectionStateChanged(BluetoothDevice device, int fromState, int toState) {
        mHandler.post(() -> connectionStateChanged(device, fromState, toState));
    }
@@ -900,6 +999,8 @@ public class BassClientService extends ProfileService {
                log("Unbonded " + device + ". Removing state machine");
                removeStateMachine(device);
            }
        } else if (toState == BluetoothProfile.STATE_CONNECTED) {
            handleReconnectingAudioSharingModeDevice(device);
        }
    }

@@ -1667,25 +1768,38 @@ public class BassClientService extends ProfileService {
        return stateMachine.getMaximumSourceCapacity();
    }

    boolean isLocalBroadcast(BluetoothLeBroadcastMetadata metaData) {
        if (metaData == null) {
            return false;
        }

    private boolean isLocalBroadcast(int sourceAdvertisingSid) {
        LeAudioService leAudioService = mServiceFactory.getLeAudioService();
        if (leAudioService == null) {
            return false;
        }

        boolean wasFound = leAudioService.getAllBroadcastMetadata()
                .stream()
                .anyMatch(meta -> {
                    return meta.getSourceAdvertisingSid() == metaData.getSourceAdvertisingSid();
        boolean wasFound =
                leAudioService.getAllBroadcastMetadata().stream()
                        .anyMatch(
                                meta -> {
                                    return meta.getSourceAdvertisingSid() == sourceAdvertisingSid;
                                });
        log("isLocalBroadcast=" + wasFound);
        return wasFound;
    }

    boolean isLocalBroadcast(BluetoothLeBroadcastMetadata metaData) {
        if (metaData == null) {
            return false;
        }

        return isLocalBroadcast(metaData.getSourceAdvertisingSid());
    }

    boolean isLocalBroadcast(BluetoothLeBroadcastReceiveState receiveState) {
        if (receiveState == null) {
            return false;
        }

        return isLocalBroadcast(receiveState.getSourceAdvertisingSid());
    }

    static void log(String msg) {
        if (BassConstants.BASS_DBG) {
            Log.d(TAG, msg);
@@ -1773,6 +1887,110 @@ public class BassClientService extends ProfileService {
        return false;
    }

    /** Return true if there is any non primary device receiving broadcast */
    private boolean isAudioSharingModeOn(Integer broadcastId) {
        if (mLocalBroadcastReceivers == null) {
            Log.w(TAG, "isAudioSharingModeOn: Local Broadcaster Receivers is not initialized");
            return false;
        }

        HashSet<BluetoothDevice> devices = mLocalBroadcastReceivers.get(broadcastId);
        if (devices == null) {
            Log.w(TAG, "isAudioSharingModeOn: No receivers receiving broadcast: " + broadcastId);
            return false;
        }

        LeAudioService leAudioService = mServiceFactory.getLeAudioService();
        if (leAudioService == null) {
            Log.d(TAG, "isAudioSharingModeOn: No available LeAudioService");
            return false;
        }

        return devices.stream().anyMatch(d -> !leAudioService.isPrimaryDevice(d));
    }

    /** Handle disconnection of potential broadcast sinks */
    public void handleDeviceDisconnection(BluetoothDevice sink, boolean isIntentional) {
        LeAudioService leAudioService = mServiceFactory.getLeAudioService();
        if (leAudioService == null) {
            Log.d(TAG, "BluetoothLeBroadcastReceiveState: No available LeAudioService");
            return;
        }

        for (Map.Entry<Integer, HashSet<BluetoothDevice>> entry :
                mLocalBroadcastReceivers.entrySet()) {
            Integer broadcastId = entry.getKey();
            HashSet<BluetoothDevice> devices = entry.getValue();

            /* If somehow there is a non playing broadcast, let's remove it */
            if (!leAudioService.isPlaying(broadcastId)) {
                Log.w(TAG, "Non playing broadcast remove from receivers list");
                mLocalBroadcastReceivers.remove(broadcastId);
                continue;
            }

            if (isIntentional) {
                /* Check if disconnecting device participated in this broadcast reception */
                if (!devices.remove(sink)) {
                    continue;
                }

                mBroadcastMetadataMap.remove(sink);

                /* Check if there is any other primary device receiving this broadcast */
                if (devices.stream()
                        .anyMatch(
                                d ->
                                        ((getConnectionState(d) == BluetoothProfile.STATE_CONNECTED)
                                                && leAudioService.isPrimaryDevice(d)))) {
                    continue;
                }

                Log.d(
                        TAG,
                        "handleIntendedDeviceDisconnection: No more potential broadcast "
                                + "(broadcast ID: "
                                + broadcastId
                                + ") receivers - stopping broadcast");
                mLocalBroadcastReceivers.remove(broadcastId);
                leAudioService.stopBroadcast(broadcastId);
            } else {
                /* Unintentional disconnection of primary device in private broadcast mode */
                if (!isAudioSharingModeOn(broadcastId)
                        && !devices.stream()
                                .anyMatch(
                                        d ->
                                                !d.equals(sink)
                                                        && (getConnectionState(d)
                                                                == BluetoothProfile
                                                                        .STATE_CONNECTED))) {
                    mLocalBroadcastReceivers.remove(broadcastId);
                    leAudioService.stopBroadcast(broadcastId);
                    continue;
                }

                /* Unintentional disconnection of primary/secondary in broadcast sharing mode */
                if (devices.stream()
                        .anyMatch(
                                d ->
                                        !d.equals(sink)
                                                && (getConnectionState(d)
                                                        == BluetoothProfile.STATE_CONNECTED))) {
                    continue;
                } else {
                    Log.d(
                            TAG,
                            "handleUnintendedDeviceDisconnection: No more potential broadcast "
                                    + "(broadcast ID: "
                                    + broadcastId
                                    + ") receivers - stopping broadcast");
                    mDialingOutTimeoutEvent = new DialingOutTimeoutEvent(broadcastId);
                    mHandler.postDelayed(mDialingOutTimeoutEvent, DIALING_OUT_TIMEOUT_MS);
                }
            }
        }
    }

    /** Request receivers to suspend broadcast sources synchronization */
    public void suspendReceiversSourceSynchronization(int broadcastId) {
        sEventLogger.logd(DBG, TAG, "Suspend receivers source synchronization: " + broadcastId);
@@ -1834,6 +2052,28 @@ public class BassClientService extends ProfileService {
        }
    }

    /** Handle broadcast state changed */
    public void notifyBroadcastStateChanged(int state, int broadcastId) {
        switch (state) {
            case BROADCAST_STATE_STOPPED:
                if (mLocalBroadcastReceivers == null) {
                    Log.e(TAG, "notifyBroadcastStateChanged: mLocalBroadcastReceivers is invalid");
                    break;
                }

                if (mLocalBroadcastReceivers.remove(broadcastId) != null) {
                    sEventLogger.logd(DBG, TAG, "Broadcast ID: " + broadcastId + ", stopped");
                }
                break;
            case BROADCAST_STATE_CONFIGURING:
            case BROADCAST_STATE_PAUSED:
            case BROADCAST_STATE_STOPPING:
            case BROADCAST_STATE_STREAMING:
            default:
                break;
        }
    }

    /**
     * Callback handler
     */
@@ -2025,6 +2265,8 @@ public class BassClientService extends ProfileService {

        void notifySourceAdded(BluetoothDevice sink, BluetoothLeBroadcastReceiveState recvState,
                int reason) {
            sService.localNotifySourceAdded(sink, recvState);

            sEventLogger.logd(
                    DBG,
                    TAG,
+4 −0
Original line number Diff line number Diff line
@@ -1701,6 +1701,7 @@ public class BassClientStateMachine extends StateMachine {
                    log("Disconnecting from " + mDevice);
                    mAllowReconnect = false;
                    if (mBluetoothGatt != null) {
                        mService.handleDeviceDisconnection(mDevice, true);
                        mBluetoothGatt.disconnect();
                        mBluetoothGatt.close();
                        mBluetoothGatt = null;
@@ -1717,6 +1718,7 @@ public class BassClientStateMachine extends StateMachine {
                        Log.w(TAG, "device is already connected to Bass" + mDevice);
                    } else {
                        Log.w(TAG, "unexpected disconnected from " + mDevice);
                        mService.handleDeviceDisconnection(mDevice, false);
                        resetBluetoothGatt();
                        cancelActiveSync(null);
                        transitionTo(mDisconnected);
@@ -2052,6 +2054,7 @@ public class BassClientStateMachine extends StateMachine {
                    Log.w(TAG, "DISCONNECT requested!: " + mDevice);
                    mAllowReconnect = false;
                    if (mBluetoothGatt != null) {
                        mService.handleDeviceDisconnection(mDevice, true);
                        mBluetoothGatt.disconnect();
                        mBluetoothGatt.close();
                        mBluetoothGatt = null;
@@ -2072,6 +2075,7 @@ public class BassClientStateMachine extends StateMachine {
                        Log.w(TAG, "should never happen from this state");
                    } else {
                        Log.w(TAG, "Unexpected disconnection " + mDevice);
                        mService.handleDeviceDisconnection(mDevice, false);
                        resetBluetoothGatt();
                        cancelActiveSync(null);
                        transitionTo(mDisconnected);
+46 −16
Original line number Diff line number Diff line
@@ -140,6 +140,7 @@ public class LeAudioService extends ProfileService {
    private HandlerThread mStateMachinesThread;
    private volatile BluetoothDevice mActiveAudioOutDevice;
    private volatile BluetoothDevice mActiveAudioInDevice;
    private volatile BluetoothDevice mActiveBroadcastAudioDevice;
    private BluetoothDevice mExposedActiveDevice;
    private LeAudioCodecConfig mLeAudioCodecConfig;
    private final Object mGroupLock = new Object();
@@ -652,6 +653,7 @@ public class LeAudioService extends ProfileService {
                        + " : no state machine");
                return false;
            }

            sm.sendMessage(LeAudioStateMachine.DISCONNECT);
        }

@@ -1138,6 +1140,16 @@ public class LeAudioService extends ProfileService {
        }
    }

    /** Return true if device is primary - is active or was active before switch to broadcast */
    public boolean isPrimaryDevice(BluetoothDevice device) {
        LeAudioDeviceDescriptor descriptor = mDeviceDescriptors.get(device);
        if (descriptor == null) {
            return false;
        }

        return descriptor.mGroupId == mUnicastGroupIdDeactivatedForBroadcastTransition;
    }

    private boolean areBroadcastsAllStopped() {
        if (mBroadcastDescriptors == null) {
            Log.e(TAG, "areBroadcastsAllStopped: Invalid Broadcast Descriptors");
@@ -1589,11 +1601,14 @@ public class LeAudioService extends ProfileService {
     * @param newDevice new supported broadcast audio device
     * @param previousDevice previous no longer supported broadcast audio device
     */
    /* TODO implement unicast overlap with connected unicast device */
    private void updateBroadcastActiveDevice(
            BluetoothDevice newDevice, BluetoothDevice previousDevice) {
        mActiveAudioOutDevice = newDevice;
            BluetoothDevice newDevice,
            BluetoothDevice previousDevice,
            boolean suppressNoisyIntent) {
        mActiveBroadcastAudioDevice = newDevice;
        mAudioManager.handleBluetoothActiveDeviceChanged(
                newDevice, previousDevice, getBroadcastProfile(true));
                newDevice, previousDevice, getBroadcastProfile(suppressNoisyIntent));
    }

    /*
@@ -2369,10 +2384,16 @@ public class LeAudioService extends ProfileService {
        BluetoothDevice unicastDevice =
                getLeadDeviceForTheGroup(mUnicastGroupIdDeactivatedForBroadcastTransition);
        if (unicastDevice == null) {
            Log.e(TAG, "EVENT_TYPE_BROADCAST_DESTROYED: No valid unicast device for group ID: "
            /* All devices from group were disconnected in meantime */
            Log.w(
                    TAG,
                    "transitionFromBroadcastToUnicast: No valid unicast device for group ID: "
                            + mUnicastGroupIdDeactivatedForBroadcastTransition);
            updateFallbackUnicastGroupIdForBroadcast(LE_AUDIO_GROUP_ID_INVALID);
            updateBroadcastActiveDevice(null, mActiveBroadcastAudioDevice, false);
            return;
        } else {
            updateBroadcastActiveDevice(null, mActiveBroadcastAudioDevice, true);
        }

        if (DBG) {
@@ -2696,19 +2717,21 @@ public class LeAudioService extends ProfileService {
                    notifyPlaybackStopped(broadcastId,
                            BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST);


                    /* Restore the Unicast stream from before the Broadcast was started. */
                    if (mUnicastGroupIdDeactivatedForBroadcastTransition
                            != LE_AUDIO_GROUP_ID_INVALID) {
                        transitionFromBroadcastToUnicast();
                    } else {
                        // Notify audio manager
                        if (mBroadcastDescriptors.values().stream()
                                .noneMatch(
                                        d ->
                                                d.mState.equals(
                                                    LeAudioStackEvent.BROADCAST_STATE_STREAMING))) {
                        updateBroadcastActiveDevice(null, mActiveAudioOutDevice);
                                                        LeAudioStackEvent
                                                                .BROADCAST_STATE_STREAMING))) {
                            updateBroadcastActiveDevice(null, mActiveBroadcastAudioDevice, false);
                        }

                    /* Restore the Unicast stream from before the Broadcast was started. */
                    if (mUnicastGroupIdDeactivatedForBroadcastTransition
                            != LE_AUDIO_GROUP_ID_INVALID) {
                        transitionFromBroadcastToUnicast();
                    }
                    destroyBroadcast(broadcastId);
                    break;
@@ -2732,7 +2755,7 @@ public class LeAudioService extends ProfileService {
                    }

                    // Notify audio manager
                    updateBroadcastActiveDevice(null, mActiveAudioOutDevice);
                    updateBroadcastActiveDevice(null, mActiveBroadcastAudioDevice, true);

                    /* Restore the Unicast stream from before the Broadcast was started. */
                    transitionFromBroadcastToUnicast();
@@ -2759,8 +2782,8 @@ public class LeAudioService extends ProfileService {
                                    d ->
                                            d.mState.equals(
                                                    LeAudioStackEvent.BROADCAST_STATE_STREAMING))) {
                        if (!Objects.equals(device, mActiveAudioOutDevice)) {
                            updateBroadcastActiveDevice(device, mActiveAudioOutDevice);
                        if (!Objects.equals(device, mActiveBroadcastAudioDevice)) {
                            updateBroadcastActiveDevice(device, mActiveBroadcastAudioDevice, true);
                        }
                    }
                    break;
@@ -2768,6 +2791,13 @@ public class LeAudioService extends ProfileService {
                    Log.e(TAG, "Invalid state of broadcast: " + descriptor.mState);
                    break;
            }

            // Notify broadcast assistant
            if (mFeatureFlags.leaudioBroadcastAudioHandoverPolicies()) {
                if (bassClientService != null) {
                    bassClientService.notifyBroadcastStateChanged(descriptor.mState, broadcastId);
                }
            }
        } else if (stackEvent.type == LeAudioStackEvent.EVENT_TYPE_BROADCAST_METADATA_CHANGED) {
            int broadcastId = stackEvent.valueInt1;
            if (stackEvent.broadcastMetadata == null) {
+244 −0

File changed.

Preview size limit exceeded, changes collapsed.

+11 −5
Original line number Diff line number Diff line
@@ -137,6 +137,7 @@ public class BassClientStateMachineTest {
        mAdapter = BluetoothAdapter.getDefaultAdapter();
        mFakeFlagsImpl = new FakeFeatureFlagsImpl();
        mFakeFlagsImpl.setFlag(Flags.FLAG_LEAUDIO_BROADCAST_MONITOR_SOURCE_SYNC_STATUS, false);
        mFakeFlagsImpl.setFlag(Flags.FLAG_LEAUDIO_BROADCAST_AUDIO_HANDOVER_POLICIES, false);
        BluetoothMethodProxy.setInstanceForTesting(mMethodProxy);
        doNothing().when(mMethodProxy).periodicAdvertisingManagerTransferSync(
                any(), any(), anyInt(), anyInt());
@@ -763,7 +764,8 @@ public class BassClientStateMachineTest {
            value[BassConstants.BCAST_RCVR_STATE_SRC_ADDR_START_IDX + i] = 0x00;
        }
        when(mBassClientService.getPeriodicAdvertisementResult(any(), anyInt())).thenReturn(null);
        when(mBassClientService.isLocalBroadcast(any())).thenReturn(true);
        when(mBassClientService.isLocalBroadcast(any(BluetoothLeBroadcastMetadata.class)))
                .thenReturn(true);
        when(characteristic.getValue()).thenReturn(value);
        mBassClientStateMachine.mPendingSourceToSwitch = mBassClientStateMachine.mPendingMetadata;

@@ -1179,7 +1181,8 @@ public class BassClientStateMachineTest {

        BluetoothLeBroadcastMetadata metadata = createBroadcastMetadata();
        // verify local broadcast doesn't require active synced source
        when(mBassClientService.isLocalBroadcast(any())).thenReturn(true);
        when(mBassClientService.isLocalBroadcast(any(BluetoothLeBroadcastMetadata.class)))
                .thenReturn(true);
        mBassClientStateMachine.sendMessage(ADD_BCAST_SOURCE, metadata);
        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());

@@ -1666,7 +1669,8 @@ public class BassClientStateMachineTest {

        BluetoothLeBroadcastMetadata metadata = createBroadcastMetadata();
        // verify local broadcast doesn't require active synced source
        when(mBassClientService.isLocalBroadcast(any())).thenReturn(true);
        when(mBassClientService.isLocalBroadcast(any(BluetoothLeBroadcastMetadata.class)))
                .thenReturn(true);
        mBassClientStateMachine.sendMessage(ADD_BCAST_SOURCE, metadata);
        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());

@@ -1700,7 +1704,8 @@ public class BassClientStateMachineTest {

        BluetoothLeBroadcastMetadata metadata = createBroadcastMetadata();
        // verify local broadcast doesn't require active synced source
        when(mBassClientService.isLocalBroadcast(any())).thenReturn(true);
        when(mBassClientService.isLocalBroadcast(any(BluetoothLeBroadcastMetadata.class)))
                .thenReturn(true);
        mBassClientStateMachine.sendMessage(ADD_BCAST_SOURCE, metadata);
        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());

@@ -1778,7 +1783,8 @@ public class BassClientStateMachineTest {
        when(mBassClientService.getCallbacks()).thenReturn(callbacks);

        BluetoothLeBroadcastMetadata metadata = createBroadcastMetadata();
        when(mBassClientService.isLocalBroadcast(any())).thenReturn(false);
        when(mBassClientService.isLocalBroadcast(any(BluetoothLeBroadcastMetadata.class)))
                .thenReturn(false);
        when(mBassClientService.getActiveSyncedSources(any())).thenReturn(null);
        when(mBassClientService.getCachedBroadcast(anyInt())).thenReturn(null);
        mBassClientStateMachine.sendMessage(ADD_BCAST_SOURCE, metadata);
Loading