Merge "[Audiosharing] Increase test coverage." into main
diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamButtonController.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamButtonController.java
index 2661072..939dd5c 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamButtonController.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamButtonController.java
@@ -27,6 +27,7 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
 import androidx.lifecycle.DefaultLifecycleObserver;
 import androidx.lifecycle.LifecycleOwner;
 import androidx.preference.PreferenceScreen;
@@ -48,7 +49,9 @@
     private static final String TAG = "AudioStreamButtonController";
     private static final String KEY = "audio_stream_button";
     private static final int SOURCE_ORIGIN_REPOSITORY = SourceOriginForLogging.REPOSITORY.ordinal();
-    private final BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback =
+
+    @VisibleForTesting
+    final BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback =
             new AudioStreamsBroadcastAssistantCallback() {
                 @Override
                 public void onSourceRemoved(BluetoothDevice sink, int sourceId, int reason) {
@@ -97,8 +100,7 @@
                 }
             };
 
-    private final AudioStreamsRepository mAudioStreamsRepository =
-            AudioStreamsRepository.getInstance();
+    private AudioStreamsRepository mAudioStreamsRepository = AudioStreamsRepository.getInstance();
     private final Executor mExecutor;
     private final AudioStreamsHelper mAudioStreamsHelper;
     private final @Nullable LocalBluetoothLeBroadcastAssistant mLeBroadcastAssistant;
@@ -228,4 +230,9 @@
     void init(int broadcastId) {
         mBroadcastId = broadcastId;
     }
+
+    @VisibleForTesting
+    void setAudioStreamsRepositoryForTesting(AudioStreamsRepository repository) {
+        mAudioStreamsRepository = repository;
+    }
 }
diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamConfirmDialog.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamConfirmDialog.java
index 6c449a4..148c776 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamConfirmDialog.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamConfirmDialog.java
@@ -31,6 +31,7 @@
 import android.util.Log;
 
 import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
 
 import com.android.settings.R;
 import com.android.settings.bluetooth.Utils;
@@ -43,9 +44,12 @@
 
 public class AudioStreamConfirmDialog extends InstrumentedDialogFragment {
     private static final String TAG = "AudioStreamConfirmDialog";
-    private static final int DEFAULT_DEVICE_NAME = R.string.audio_streams_dialog_default_device;
+
+    @VisibleForTesting
+    static final int DEFAULT_DEVICE_NAME = R.string.audio_streams_dialog_default_device;
+
     private Context mContext;
-    @Nullable private Activity mActivity;
+    @VisibleForTesting @Nullable Activity mActivity;
     @Nullable private BluetoothLeBroadcastMetadata mBroadcastMetadata;
     @Nullable private BluetoothDevice mConnectedDevice;
     private int mAudioStreamConfirmDialogId = SettingsEnums.PAGE_UNKNOWN;
diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamHeaderController.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamHeaderController.java
index 860e62e..e1a178d 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamHeaderController.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamHeaderController.java
@@ -54,7 +54,9 @@
     private final Executor mExecutor;
     private final AudioStreamsHelper mAudioStreamsHelper;
     @Nullable private final LocalBluetoothLeBroadcastAssistant mLeBroadcastAssistant;
-    private final BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback =
+
+    @VisibleForTesting
+    final BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback =
             new AudioStreamsBroadcastAssistantCallback() {
                 @Override
                 public void onSourceRemoved(BluetoothDevice sink, int sourceId, int reason) {
diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsDashboardFragment.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsDashboardFragment.java
index ce32cdb..ae5cb6e 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsDashboardFragment.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsDashboardFragment.java
@@ -23,7 +23,6 @@
 import android.bluetooth.BluetoothLeBroadcastMetadata;
 import android.content.Context;
 import android.content.Intent;
-import android.os.Bundle;
 import android.util.Log;
 
 import androidx.annotation.Nullable;
@@ -64,11 +63,6 @@
     }
 
     @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-    }
-
-    @Override
     public void onAttach(Context context) {
         super.onAttach(context);
         use(AudioStreamsScanQrCodeController.class).setFragment(this);
@@ -92,11 +86,6 @@
     }
 
     @Override
-    public void onActivityCreated(Bundle savedInstanceState) {
-        super.onActivityCreated(savedInstanceState);
-    }
-
-    @Override
     public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
         super.onActivityResult(requestCode, resultCode, data);
         if (DEBUG) {
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamButtonControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamButtonControllerTest.java
index cbf1432..c6fb361 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamButtonControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamButtonControllerTest.java
@@ -16,22 +16,36 @@
 
 package com.android.settings.connecteddevice.audiosharing.audiostreams;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.settings.SettingsEnums;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothLeBroadcastAssistant;
+import android.bluetooth.BluetoothLeBroadcastMetadata;
 import android.bluetooth.BluetoothLeBroadcastReceiveState;
 import android.content.Context;
 import android.view.View;
 
+import androidx.lifecycle.LifecycleOwner;
 import androidx.preference.PreferenceScreen;
 import androidx.test.core.app.ApplicationProvider;
 
 import com.android.settings.R;
 import com.android.settings.connecteddevice.audiosharing.audiostreams.testshadows.ShadowAudioStreamsHelper;
+import com.android.settings.testutils.FakeFeatureFactory;
 import com.android.settings.testutils.shadow.ShadowThreadUtils;
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
+import com.android.settingslib.core.lifecycle.Lifecycle;
 import com.android.settingslib.widget.ActionButtonsPreference;
 
 import org.junit.After;
@@ -39,14 +53,17 @@
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.annotation.Config;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.concurrent.Executor;
 
 @RunWith(RobolectricTestRunner.class)
 @Config(
@@ -63,14 +80,23 @@
     @Mock private AudioStreamsHelper mAudioStreamsHelper;
     @Mock private PreferenceScreen mScreen;
     @Mock private BluetoothLeBroadcastReceiveState mBroadcastReceiveState;
+    @Mock private LocalBluetoothLeBroadcastAssistant mAssistant;
+    @Mock private AudioStreamsRepository mRepository;
     @Mock private ActionButtonsPreference mPreference;
+    private Lifecycle mLifecycle;
+    private LifecycleOwner mLifecycleOwner;
+    private FakeFeatureFactory mFeatureFactory;
     private AudioStreamButtonController mController;
 
     @Before
     public void setUp() {
         ShadowAudioStreamsHelper.setUseMock(mAudioStreamsHelper);
+        when(mAudioStreamsHelper.getLeBroadcastAssistant()).thenReturn(mAssistant);
+        mFeatureFactory = FakeFeatureFactory.setupForTest();
         mController = new AudioStreamButtonController(mContext, KEY);
         mController.init(BROADCAST_ID);
+        mLifecycleOwner = () -> mLifecycle;
+        mLifecycle = new Lifecycle(mLifecycleOwner);
         when(mScreen.findPreference(KEY)).thenReturn(mPreference);
         when(mPreference.getContext()).thenReturn(mContext);
         when(mPreference.setButton1Text(anyInt())).thenReturn(mPreference);
@@ -86,6 +112,40 @@
     }
 
     @Test
+    public void onStart_registerCallbacks() {
+        mController.onStart(mLifecycleOwner);
+        verify(mAssistant)
+                .registerServiceCallBack(
+                        any(Executor.class), any(BluetoothLeBroadcastAssistant.Callback.class));
+    }
+
+    @Test
+    public void onStart_profileNull_doNothing() {
+        when(mAudioStreamsHelper.getLeBroadcastAssistant()).thenReturn(null);
+        mController = new AudioStreamButtonController(mContext, KEY);
+        mController.onStart(mLifecycleOwner);
+        verify(mAssistant, never())
+                .registerServiceCallBack(
+                        any(Executor.class), any(BluetoothLeBroadcastAssistant.Callback.class));
+    }
+
+    @Test
+    public void onStop_unregisterCallbacks() {
+        mController.onStop(mLifecycleOwner);
+        verify(mAssistant)
+                .unregisterServiceCallBack(any(BluetoothLeBroadcastAssistant.Callback.class));
+    }
+
+    @Test
+    public void onStop_profileNull_doNothing() {
+        when(mAudioStreamsHelper.getLeBroadcastAssistant()).thenReturn(null);
+        mController = new AudioStreamButtonController(mContext, KEY);
+        mController.onStop(mLifecycleOwner);
+        verify(mAssistant, never())
+                .unregisterServiceCallBack(any(BluetoothLeBroadcastAssistant.Callback.class));
+    }
+
+    @Test
     public void testDisplayPreference_sourceConnected_setDisconnectButton() {
         when(mAudioStreamsHelper.getAllConnectedSources())
                 .thenReturn(List.of(mBroadcastReceiveState));
@@ -96,18 +156,133 @@
         verify(mPreference).setButton1Enabled(true);
         verify(mPreference).setButton1Text(R.string.audio_streams_disconnect);
         verify(mPreference).setButton1Icon(com.android.settings.R.drawable.ic_settings_close);
-        verify(mPreference).setButton1OnClickListener(any(View.OnClickListener.class));
+
+        ArgumentCaptor<View.OnClickListener> listenerCaptor =
+                ArgumentCaptor.forClass(View.OnClickListener.class);
+        verify(mPreference).setButton1OnClickListener(listenerCaptor.capture());
+        var listener = listenerCaptor.getValue();
+
+        assertThat(listener).isNotNull();
+        listener.onClick(mock(View.class));
+        verify(mAudioStreamsHelper).removeSource(BROADCAST_ID);
+        verify(mPreference).setButton1Enabled(false);
+        verify(mFeatureFactory.metricsFeatureProvider)
+                .action(any(), eq(SettingsEnums.ACTION_AUDIO_STREAM_LEAVE_BUTTON_CLICK));
     }
 
     @Test
     public void testDisplayPreference_sourceNotConnected_setConnectButton() {
         when(mAudioStreamsHelper.getAllConnectedSources()).thenReturn(Collections.emptyList());
+        mController.setAudioStreamsRepositoryForTesting(mRepository);
+        var metadataToRejoin = mock(BluetoothLeBroadcastMetadata.class);
+        when(mRepository.getSavedMetadata(any(), anyInt())).thenReturn(metadataToRejoin);
 
         mController.displayPreference(mScreen);
 
         verify(mPreference).setButton1Enabled(true);
         verify(mPreference).setButton1Text(R.string.audio_streams_connect);
         verify(mPreference).setButton1Icon(com.android.settings.R.drawable.ic_add_24dp);
-        verify(mPreference).setButton1OnClickListener(any(View.OnClickListener.class));
+
+        ArgumentCaptor<View.OnClickListener> listenerCaptor =
+                ArgumentCaptor.forClass(View.OnClickListener.class);
+        verify(mPreference).setButton1OnClickListener(listenerCaptor.capture());
+        var listener = listenerCaptor.getValue();
+
+        assertThat(listener).isNotNull();
+        listener.onClick(mock(View.class));
+        verify(mAudioStreamsHelper).addSource(metadataToRejoin);
+        verify(mPreference).setButton1Enabled(false);
+        verify(mFeatureFactory.metricsFeatureProvider)
+                .action(any(), eq(SettingsEnums.ACTION_AUDIO_STREAM_JOIN), anyInt());
+    }
+
+    @Test
+    public void testCallback_onSourceRemoved_updateButton() {
+        when(mAudioStreamsHelper.getAllConnectedSources()).thenReturn(Collections.emptyList());
+
+        mController.displayPreference(mScreen);
+        mController.mBroadcastAssistantCallback.onSourceRemoved(
+                mock(BluetoothDevice.class), /* sourceId= */ 0, /* reason= */ 0);
+
+        // Called twice, once in displayPreference, the other one in callback
+        verify(mPreference, times(2)).setButton1Enabled(true);
+        verify(mPreference, times(2)).setButton1Text(R.string.audio_streams_connect);
+        verify(mPreference, times(2)).setButton1Icon(com.android.settings.R.drawable.ic_add_24dp);
+    }
+
+    @Test
+    public void testCallback_onSourceRemovedFailed_updateButton() {
+        when(mAudioStreamsHelper.getAllConnectedSources())
+                .thenReturn(List.of(mBroadcastReceiveState));
+        when(mBroadcastReceiveState.getBroadcastId()).thenReturn(BROADCAST_ID);
+
+        mController.displayPreference(mScreen);
+        mController.mBroadcastAssistantCallback.onSourceRemoveFailed(
+                mock(BluetoothDevice.class), /* sourceId= */ 0, /* reason= */ 0);
+
+        verify(mFeatureFactory.metricsFeatureProvider)
+                .action(any(), eq(SettingsEnums.ACTION_AUDIO_STREAM_LEAVE_FAILED));
+
+        // Called twice, once in displayPreference, the other one in callback
+        verify(mPreference, times(2)).setButton1Enabled(true);
+        verify(mPreference, times(2)).setButton1Text(R.string.audio_streams_disconnect);
+        verify(mPreference, times(2))
+                .setButton1Icon(com.android.settings.R.drawable.ic_settings_close);
+    }
+
+    @Test
+    public void testCallback_onReceiveStateChanged_updateButton() {
+        when(mAudioStreamsHelper.getAllConnectedSources())
+                .thenReturn(List.of(mBroadcastReceiveState));
+        when(mBroadcastReceiveState.getBroadcastId()).thenReturn(BROADCAST_ID);
+        BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class);
+        List<Long> bisSyncState = new ArrayList<>();
+        bisSyncState.add(1L);
+        when(state.getBisSyncState()).thenReturn(bisSyncState);
+
+        mController.displayPreference(mScreen);
+        mController.mBroadcastAssistantCallback.onReceiveStateChanged(
+                mock(BluetoothDevice.class), /* sourceId= */ 0, state);
+
+        verify(mFeatureFactory.metricsFeatureProvider)
+                .action(any(), eq(SettingsEnums.ACTION_AUDIO_STREAM_JOIN_SUCCEED), anyInt());
+
+        // Called twice, once in displayPreference, the other one in callback
+        verify(mPreference, times(2)).setButton1Enabled(true);
+        verify(mPreference, times(2)).setButton1Text(R.string.audio_streams_disconnect);
+        verify(mPreference, times(2))
+                .setButton1Icon(com.android.settings.R.drawable.ic_settings_close);
+    }
+
+    @Test
+    public void testCallback_onSourceAddFailed_updateButton() {
+        when(mAudioStreamsHelper.getAllConnectedSources()).thenReturn(Collections.emptyList());
+
+        mController.displayPreference(mScreen);
+        mController.mBroadcastAssistantCallback.onSourceAddFailed(
+                mock(BluetoothDevice.class),
+                mock(BluetoothLeBroadcastMetadata.class),
+                /* reason= */ 0);
+
+        verify(mFeatureFactory.metricsFeatureProvider)
+                .action(any(), eq(SettingsEnums.ACTION_AUDIO_STREAM_JOIN_FAILED_OTHER), anyInt());
+
+        // Called twice, once in displayPreference, the other one in callback
+        verify(mPreference, times(2)).setButton1Enabled(true);
+        verify(mPreference, times(2)).setButton1Text(R.string.audio_streams_connect);
+        verify(mPreference, times(2)).setButton1Icon(com.android.settings.R.drawable.ic_add_24dp);
+    }
+
+    @Test
+    public void testCallback_onSourceLost_updateButton() {
+        when(mAudioStreamsHelper.getAllConnectedSources()).thenReturn(Collections.emptyList());
+
+        mController.displayPreference(mScreen);
+        mController.mBroadcastAssistantCallback.onSourceLost(/* broadcastId= */ 0);
+
+        // Called twice, once in displayPreference, the other one in callback
+        verify(mPreference, times(2)).setButton1Enabled(true);
+        verify(mPreference, times(2)).setButton1Text(R.string.audio_streams_connect);
+        verify(mPreference, times(2)).setButton1Icon(com.android.settings.R.drawable.ic_add_24dp);
     }
 }
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamConfirmDialogActivityTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamConfirmDialogActivityTest.java
index e967a12..1f05cbb 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamConfirmDialogActivityTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamConfirmDialogActivityTest.java
@@ -18,28 +18,132 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothStatusCodes;
+import android.platform.test.flag.junit.SetFlagsRule;
+
+import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
+import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
+import com.android.settingslib.bluetooth.VolumeControlProfile;
+import com.android.settingslib.flags.Flags;
+
+import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
 import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadow.api.Shadow;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(
+        shadows = {
+            ShadowBluetoothAdapter.class,
+            ShadowBluetoothUtils.class,
+        })
 public class AudioStreamConfirmDialogActivityTest {
+    @Rule public final MockitoRule mocks = MockitoJUnit.rule();
+    @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+    @Mock private LocalBluetoothManager mLocalBluetoothManager;
+    @Mock private LocalBluetoothProfileManager mLocalBluetoothProfileManager;
+    @Mock private LocalBluetoothLeBroadcast mBroadcast;
+    @Mock private LocalBluetoothLeBroadcastAssistant mAssistant;
+    @Mock private VolumeControlProfile mVolumeControl;
+    private ShadowBluetoothAdapter mShadowBluetoothAdapter;
     private AudioStreamConfirmDialogActivity mActivity;
 
     @Before
     public void setUp() {
-        mActivity = Robolectric.buildActivity(AudioStreamConfirmDialogActivity.class).get();
+        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+        mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
+        mShadowBluetoothAdapter.setEnabled(true);
+        mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
+                BluetoothStatusCodes.FEATURE_SUPPORTED);
+        mShadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
+                BluetoothStatusCodes.FEATURE_SUPPORTED);
+        ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager;
+        when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBluetoothProfileManager);
+        when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(mBroadcast);
+        when(mLocalBluetoothProfileManager.getLeAudioBroadcastAssistantProfile())
+                .thenReturn(mAssistant);
+        when(mLocalBluetoothProfileManager.getVolumeControlProfile()).thenReturn(mVolumeControl);
+        when(mBroadcast.isProfileReady()).thenReturn(true);
+        when(mAssistant.isProfileReady()).thenReturn(true);
+        when(mVolumeControl.isProfileReady()).thenReturn(true);
+    }
+
+    @After
+    public void tearDown() {
+        ShadowBluetoothUtils.reset();
     }
 
     @Test
     public void isValidFragment_returnsTrue() {
+        mActivity = Robolectric.setupActivity(AudioStreamConfirmDialogActivity.class);
         assertThat(mActivity.isValidFragment(AudioStreamConfirmDialog.class.getName())).isTrue();
     }
 
     @Test
     public void isValidFragment_returnsFalse() {
+        mActivity = Robolectric.setupActivity(AudioStreamConfirmDialogActivity.class);
         assertThat(mActivity.isValidFragment("")).isFalse();
     }
+
+    @Test
+    public void isToolbarEnabled_returnsFalse() {
+        mActivity = Robolectric.setupActivity(AudioStreamConfirmDialogActivity.class);
+        assertThat(mActivity.isToolbarEnabled()).isFalse();
+    }
+
+    @Test
+    public void setupActivity_serviceNotReady_registerCallback() {
+        when(mBroadcast.isProfileReady()).thenReturn(false);
+        mActivity = Robolectric.setupActivity(AudioStreamConfirmDialogActivity.class);
+
+        verify(mLocalBluetoothProfileManager).addServiceListener(any());
+    }
+
+    @Test
+    public void setupActivity_serviceNotReady_registerCallback_onServiceCallback() {
+        when(mBroadcast.isProfileReady()).thenReturn(false);
+        mActivity = Robolectric.setupActivity(AudioStreamConfirmDialogActivity.class);
+
+        verify(mLocalBluetoothProfileManager).addServiceListener(any());
+
+        when(mBroadcast.isProfileReady()).thenReturn(true);
+        mActivity.onServiceConnected();
+        verify(mLocalBluetoothProfileManager).removeServiceListener(any());
+
+        mActivity.onServiceDisconnected();
+        // Do nothing.
+    }
+
+    @Test
+    public void setupActivity_serviceReady_doNothing() {
+        mActivity = Robolectric.setupActivity(AudioStreamConfirmDialogActivity.class);
+
+        verify(mLocalBluetoothProfileManager, never()).addServiceListener(any());
+    }
+
+    @Test
+    public void onStop_unregisterCallback() {
+        mActivity = Robolectric.setupActivity(AudioStreamConfirmDialogActivity.class);
+        mActivity.onStop();
+
+        verify(mLocalBluetoothProfileManager).removeServiceListener(any());
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamConfirmDialogTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamConfirmDialogTest.java
index c7aafe8..601c432 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamConfirmDialogTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamConfirmDialogTest.java
@@ -16,14 +16,21 @@
 
 package com.android.settings.connecteddevice.audiosharing.audiostreams;
 
+import static android.app.settings.SettingsEnums.DIALOG_AUDIO_STREAM_CONFIRM_LISTEN;
+
+import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamConfirmDialog.DEFAULT_DEVICE_NAME;
 import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamsDashboardFragment.KEY_BROADCAST_METADATA;
 
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.robolectric.shadows.ShadowLooper.shadowMainLooper;
 
+import android.app.Dialog;
 import android.app.settings.SettingsEnums;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
@@ -127,6 +134,8 @@
 
         assertThat(mDialogFragment.getMetricsCategory())
                 .isEqualTo(SettingsEnums.DIALOG_AUDIO_STREAM_CONFIRM_FEATURE_UNSUPPORTED);
+        assertThat(mDialogFragment.mActivity).isNotNull();
+        mDialogFragment.mActivity = spy(mDialogFragment.mActivity);
 
         var dialog = mDialogFragment.getDialog();
         assertThat(dialog).isNotNull();
@@ -152,6 +161,10 @@
         assertThat(rightButton).isNotNull();
         assertThat(rightButton.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(rightButton.hasOnClickListeners()).isTrue();
+
+        rightButton.callOnClick();
+        assertThat(dialog.isShowing()).isFalse();
+        verify(mDialogFragment.mActivity).finish();
     }
 
     @Test
@@ -165,6 +178,8 @@
 
         assertThat(mDialogFragment.getMetricsCategory())
                 .isEqualTo(SettingsEnums.DIALOG_AUDIO_STREAM_CONFIRM_NO_LE_DEVICE);
+        assertThat(mDialogFragment.mActivity).isNotNull();
+        mDialogFragment.mActivity = spy(mDialogFragment.mActivity);
 
         var dialog = mDialogFragment.getDialog();
         assertThat(dialog).isNotNull();
@@ -184,11 +199,20 @@
         View leftButton = dialog.findViewById(R.id.left_button);
         assertThat(leftButton).isNotNull();
         assertThat(leftButton.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(leftButton.hasOnClickListeners()).isTrue();
+
+        leftButton.callOnClick();
+        assertThat(dialog.isShowing()).isFalse();
+
         Button rightButton = dialog.findViewById(R.id.right_button);
         assertThat(rightButton).isNotNull();
         assertThat(rightButton.getText())
                 .isEqualTo(mContext.getString(R.string.audio_streams_dialog_no_le_device_button));
         assertThat(rightButton.hasOnClickListeners()).isTrue();
+
+        rightButton.callOnClick();
+        assertThat(dialog.isShowing()).isFalse();
+        verify(mDialogFragment.mActivity, times(2)).finish();
     }
 
     @Test
@@ -207,6 +231,8 @@
 
         assertThat(mDialogFragment.getMetricsCategory())
                 .isEqualTo(SettingsEnums.DIALOG_AUDIO_STREAM_CONFIRM_DATA_ERROR);
+        assertThat(mDialogFragment.mActivity).isNotNull();
+        mDialogFragment.mActivity = spy(mDialogFragment.mActivity);
 
         var dialog = mDialogFragment.getDialog();
         assertThat(dialog).isNotNull();
@@ -231,6 +257,10 @@
         assertThat(rightButton).isNotNull();
         assertThat(rightButton.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(rightButton.hasOnClickListeners()).isTrue();
+
+        rightButton.callOnClick();
+        assertThat(dialog.isShowing()).isFalse();
+        verify(mDialogFragment.mActivity).finish();
     }
 
     @Test
@@ -252,6 +282,8 @@
 
         assertThat(mDialogFragment.getMetricsCategory())
                 .isEqualTo(SettingsEnums.DIALOG_AUDIO_STREAM_CONFIRM_DATA_ERROR);
+        assertThat(mDialogFragment.mActivity).isNotNull();
+        mDialogFragment.mActivity = spy(mDialogFragment.mActivity);
 
         var dialog = mDialogFragment.getDialog();
         assertThat(dialog).isNotNull();
@@ -276,6 +308,10 @@
         assertThat(rightButton).isNotNull();
         assertThat(rightButton.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(rightButton.hasOnClickListeners()).isTrue();
+
+        rightButton.callOnClick();
+        assertThat(dialog.isShowing()).isFalse();
+        verify(mDialogFragment.mActivity).finish();
     }
 
     @Test
@@ -283,7 +319,7 @@
         List<BluetoothDevice> devices = new ArrayList<>();
         devices.add(mBluetoothDevice);
         when(mAssistant.getDevicesMatchingConnectionStates(any())).thenReturn(devices);
-        when(mBluetoothDevice.getAlias()).thenReturn(DEVICE_NAME);
+        when(mBluetoothDevice.getAlias()).thenReturn("");
 
         Intent intent = new Intent();
         intent.putExtra(KEY_BROADCAST_METADATA, VALID_METADATA);
@@ -296,9 +332,11 @@
         shadowMainLooper().idle();
 
         assertThat(mDialogFragment.getMetricsCategory())
-                .isEqualTo(SettingsEnums.DIALOG_AUDIO_STREAM_CONFIRM_LISTEN);
+                .isEqualTo(DIALOG_AUDIO_STREAM_CONFIRM_LISTEN);
+        assertThat(mDialogFragment.mActivity).isNotNull();
+        mDialogFragment.mActivity = spy(mDialogFragment.mActivity);
 
-        var dialog = mDialogFragment.getDialog();
+        Dialog dialog = mDialogFragment.getDialog();
         assertThat(dialog).isNotNull();
         assertThat(dialog.isShowing()).isTrue();
         TextView title = dialog.findViewById(R.id.dialog_title);
@@ -311,17 +349,27 @@
         assertThat(subtitle1.getVisibility()).isEqualTo(View.VISIBLE);
         TextView subtitle2 = dialog.findViewById(R.id.dialog_subtitle_2);
         assertThat(subtitle2).isNotNull();
+        var defaultName = mContext.getString(DEFAULT_DEVICE_NAME);
         assertThat(subtitle2.getText())
                 .isEqualTo(
                         mContext.getString(
-                                R.string.audio_streams_dialog_control_volume, DEVICE_NAME));
+                                R.string.audio_streams_dialog_control_volume, defaultName));
         View leftButton = dialog.findViewById(R.id.left_button);
         assertThat(leftButton).isNotNull();
         assertThat(leftButton.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(leftButton.hasOnClickListeners()).isTrue();
+
+        leftButton.callOnClick();
+        assertThat(dialog.isShowing()).isFalse();
+
         Button rightButton = dialog.findViewById(R.id.right_button);
         assertThat(rightButton).isNotNull();
         assertThat(rightButton.getText())
                 .isEqualTo(mContext.getString(R.string.audio_streams_dialog_listen));
         assertThat(rightButton.hasOnClickListeners()).isTrue();
+
+        rightButton.callOnClick();
+        assertThat(dialog.isShowing()).isFalse();
+        verify(mDialogFragment.mActivity, times(2)).finish();
     }
 }
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamDetailsFragmentTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamDetailsFragmentTest.java
index 724c772..46d481a 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamDetailsFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamDetailsFragmentTest.java
@@ -16,22 +16,48 @@
 
 package com.android.settings.connecteddevice.audiosharing.audiostreams;
 
+import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamDetailsFragment.BROADCAST_ID_ARG;
+import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamDetailsFragment.BROADCAST_NAME_ARG;
+
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.os.Bundle;
+
+import androidx.test.core.app.ApplicationProvider;
+
 import com.android.settings.R;
+import com.android.settingslib.core.AbstractPreferenceController;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
 import org.robolectric.RobolectricTestRunner;
 
 @RunWith(RobolectricTestRunner.class)
 public class AudioStreamDetailsFragmentTest {
-    private AudioStreamDetailsFragment mFragment;
+    @Rule public final MockitoRule mocks = MockitoJUnit.rule();
+    private static final String BROADCAST_NAME = "name";
+    private static final int BROADCAST_ID = 1;
+    private final Context mContext = ApplicationProvider.getApplicationContext();
+    @Mock private AudioStreamHeaderController mHeaderController;
+    @Mock private AudioStreamButtonController mButtonController;
+    private TestFragment mFragment;
 
     @Before
     public void setUp() {
-        mFragment = new AudioStreamDetailsFragment();
+        mFragment = spy(new TestFragment());
+        doReturn(mHeaderController).when(mFragment).use(AudioStreamHeaderController.class);
+        doReturn(mButtonController).when(mFragment).use(AudioStreamButtonController.class);
     }
 
     @Test
@@ -44,4 +70,29 @@
     public void getLogTag_returnsCorrectTag() {
         assertThat(mFragment.getLogTag()).isEqualTo(AudioStreamDetailsFragment.TAG);
     }
+
+    @Test
+    public void getMetricsCategory_returnsCorrectEnum() {
+        assertThat(mFragment.getMetricsCategory()).isEqualTo(SettingsEnums.AUDIO_STREAM_DETAIL);
+    }
+
+    @Test
+    public void onAttach_getArguments() {
+        Bundle bundle = new Bundle();
+        bundle.putString(BROADCAST_NAME_ARG, BROADCAST_NAME);
+        bundle.putInt(BROADCAST_ID_ARG, BROADCAST_ID);
+        mFragment.setArguments(bundle);
+
+        mFragment.onAttach(mContext);
+
+        verify(mButtonController).init(BROADCAST_ID);
+        verify(mHeaderController).init(mFragment, BROADCAST_NAME, BROADCAST_ID);
+    }
+
+    public static class TestFragment extends AudioStreamDetailsFragment {
+        @Override
+        protected <T extends AbstractPreferenceController> T use(Class<T> clazz) {
+            return super.use(clazz);
+        }
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamHeaderControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamHeaderControllerTest.java
index 0cd5d61..327090d 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamHeaderControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamHeaderControllerTest.java
@@ -19,12 +19,20 @@
 import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamHeaderController.AUDIO_STREAM_HEADER_LISTENING_NOW_SUMMARY;
 import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamHeaderController.AUDIO_STREAM_HEADER_NOT_LISTENING_SUMMARY;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothLeBroadcastAssistant;
 import android.bluetooth.BluetoothLeBroadcastReceiveState;
 import android.content.Context;
+import android.graphics.drawable.Drawable;
 
+import androidx.lifecycle.LifecycleOwner;
 import androidx.preference.PreferenceScreen;
 import androidx.test.core.app.ApplicationProvider;
 
@@ -32,6 +40,8 @@
 import com.android.settings.connecteddevice.audiosharing.audiostreams.testshadows.ShadowEntityHeaderController;
 import com.android.settings.testutils.shadow.ShadowThreadUtils;
 import com.android.settings.widget.EntityHeaderController;
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
+import com.android.settingslib.core.lifecycle.Lifecycle;
 import com.android.settingslib.widget.LayoutPreference;
 
 import org.junit.After;
@@ -45,8 +55,10 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.annotation.Config;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.concurrent.Executor;
 
 @RunWith(RobolectricTestRunner.class)
 @Config(
@@ -65,15 +77,21 @@
     @Mock private AudioStreamsHelper mAudioStreamsHelper;
     @Mock private PreferenceScreen mScreen;
     @Mock private BluetoothLeBroadcastReceiveState mBroadcastReceiveState;
+    @Mock private LocalBluetoothLeBroadcastAssistant mAssistant;
     @Mock private AudioStreamDetailsFragment mFragment;
     @Mock private LayoutPreference mPreference;
     @Mock private EntityHeaderController mHeaderController;
+    private Lifecycle mLifecycle;
+    private LifecycleOwner mLifecycleOwner;
     private AudioStreamHeaderController mController;
 
     @Before
     public void setUp() {
         ShadowEntityHeaderController.setUseMock(mHeaderController);
         ShadowAudioStreamsHelper.setUseMock(mAudioStreamsHelper);
+        when(mAudioStreamsHelper.getLeBroadcastAssistant()).thenReturn(mAssistant);
+        mLifecycleOwner = () -> mLifecycle;
+        mLifecycle = new Lifecycle(mLifecycleOwner);
         mController = new AudioStreamHeaderController(mContext, KEY);
         mController.init(mFragment, BROADCAST_NAME, BROADCAST_ID);
         when(mScreen.findPreference(KEY)).thenReturn(mPreference);
@@ -88,6 +106,40 @@
     }
 
     @Test
+    public void onStart_registerCallbacks() {
+        mController.onStart(mLifecycleOwner);
+        verify(mAssistant)
+                .registerServiceCallBack(
+                        any(Executor.class), any(BluetoothLeBroadcastAssistant.Callback.class));
+    }
+
+    @Test
+    public void onStart_profileNull_doNothing() {
+        when(mAudioStreamsHelper.getLeBroadcastAssistant()).thenReturn(null);
+        mController = new AudioStreamHeaderController(mContext, KEY);
+        mController.onStart(mLifecycleOwner);
+        verify(mAssistant, never())
+                .registerServiceCallBack(
+                        any(Executor.class), any(BluetoothLeBroadcastAssistant.Callback.class));
+    }
+
+    @Test
+    public void onStop_unregisterCallbacks() {
+        mController.onStop(mLifecycleOwner);
+        verify(mAssistant)
+                .unregisterServiceCallBack(any(BluetoothLeBroadcastAssistant.Callback.class));
+    }
+
+    @Test
+    public void onStop_profileNull_doNothing() {
+        when(mAudioStreamsHelper.getLeBroadcastAssistant()).thenReturn(null);
+        mController = new AudioStreamHeaderController(mContext, KEY);
+        mController.onStop(mLifecycleOwner);
+        verify(mAssistant, never())
+                .unregisterServiceCallBack(any(BluetoothLeBroadcastAssistant.Callback.class));
+    }
+
+    @Test
     public void testDisplayPreference_sourceConnected_setSummary() {
         when(mAudioStreamsHelper.getAllConnectedSources())
                 .thenReturn(List.of(mBroadcastReceiveState));
@@ -96,9 +148,11 @@
         mController.displayPreference(mScreen);
 
         verify(mHeaderController).setLabel(BROADCAST_NAME);
+        verify(mHeaderController).setIcon(any(Drawable.class));
         verify(mHeaderController)
                 .setSummary(mContext.getString(AUDIO_STREAM_HEADER_LISTENING_NOW_SUMMARY));
         verify(mHeaderController).done(true);
+        verify(mScreen).addPreference(any());
     }
 
     @Test
@@ -108,7 +162,54 @@
         mController.displayPreference(mScreen);
 
         verify(mHeaderController).setLabel(BROADCAST_NAME);
+        verify(mHeaderController).setIcon(any(Drawable.class));
         verify(mHeaderController).setSummary(AUDIO_STREAM_HEADER_NOT_LISTENING_SUMMARY);
         verify(mHeaderController).done(true);
+        verify(mScreen).addPreference(any());
+    }
+
+    @Test
+    public void testCallback_onSourceRemoved_updateButton() {
+        when(mAudioStreamsHelper.getAllConnectedSources()).thenReturn(Collections.emptyList());
+
+        mController.displayPreference(mScreen);
+        mController.mBroadcastAssistantCallback.onSourceRemoved(
+                mock(BluetoothDevice.class), /* sourceId= */ 0, /* reason= */ 0);
+
+        // Called twice, once in displayPreference, the other one in callback
+        verify(mHeaderController, times(2)).setSummary(AUDIO_STREAM_HEADER_NOT_LISTENING_SUMMARY);
+        verify(mHeaderController, times(2)).done(true);
+    }
+
+    @Test
+    public void testCallback_onSourceLost_updateButton() {
+        when(mAudioStreamsHelper.getAllConnectedSources()).thenReturn(Collections.emptyList());
+
+        mController.displayPreference(mScreen);
+        mController.mBroadcastAssistantCallback.onSourceLost(/* broadcastId= */ 1);
+
+        // Called twice, once in displayPreference, the other one in callback
+        verify(mHeaderController, times(2)).setSummary(AUDIO_STREAM_HEADER_NOT_LISTENING_SUMMARY);
+        verify(mHeaderController, times(2)).done(true);
+    }
+
+    @Test
+    public void testCallback_onReceiveStateChanged_updateButton() {
+        when(mAudioStreamsHelper.getAllConnectedSources())
+                .thenReturn(List.of(mBroadcastReceiveState));
+        when(mBroadcastReceiveState.getBroadcastId()).thenReturn(BROADCAST_ID);
+        BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class);
+        List<Long> bisSyncState = new ArrayList<>();
+        bisSyncState.add(1L);
+        when(state.getBisSyncState()).thenReturn(bisSyncState);
+
+        mController.displayPreference(mScreen);
+        mController.mBroadcastAssistantCallback.onReceiveStateChanged(
+                mock(BluetoothDevice.class), /* sourceId= */ 0, state);
+
+        // Called twice, once in displayPreference, the other one in callback
+        verify(mHeaderController, times(2))
+                .setSummary(mContext.getString(AUDIO_STREAM_HEADER_LISTENING_NOW_SUMMARY));
+        verify(mHeaderController, times(2)).done(true);
     }
 }
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsDashboardFragmentTest.java
index 9058ab6..dd3d8b7 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsDashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsDashboardFragmentTest.java
@@ -22,18 +22,25 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 
 import android.app.Activity;
+import android.app.settings.SettingsEnums;
+import android.bluetooth.BluetoothLeBroadcastMetadata;
 import android.content.Context;
 import android.content.Intent;
+import android.os.Bundle;
 
 import androidx.test.core.app.ApplicationProvider;
 
 import com.android.settings.R;
+import com.android.settings.testutils.FakeFeatureFactory;
 import com.android.settingslib.core.AbstractPreferenceController;
 
 import org.junit.Before;
@@ -53,12 +60,14 @@
                     + "MD:BgNwVGVzdA==;AS:1;PI:A0;NS:1;BS:3;NB:2;SM:BQNUZXN0BARlbmc=;;";
 
     private Context mContext;
+    private FakeFeatureFactory mFeatureFactory;
     private AudioStreamsProgressCategoryController mController;
     private TestFragment mTestFragment;
 
     @Before
     public void setUp() {
         mContext = ApplicationProvider.getApplicationContext();
+        mFeatureFactory = FakeFeatureFactory.setupForTest();
         mTestFragment = spy(new TestFragment());
         doReturn(mContext).when(mTestFragment).getContext();
         mController = spy(new AudioStreamsProgressCategoryController(mContext, "key"));
@@ -114,6 +123,28 @@
         mTestFragment.onActivityResult(
                 REQUEST_SCAN_BT_BROADCAST_QR_CODE, Activity.RESULT_OK, intent);
         verify(mController).setSourceFromQrCode(any(), any());
+        verify(mFeatureFactory.metricsFeatureProvider)
+                .action(
+                        any(),
+                        eq(SettingsEnums.ACTION_AUDIO_STREAM_QR_CODE_SCAN_SUCCEED),
+                        anyInt());
+    }
+
+    @Test
+    public void onAttach_hasArgument() {
+        BluetoothLeBroadcastMetadata data = mock(BluetoothLeBroadcastMetadata.class);
+        Bundle bundle = new Bundle();
+        bundle.putParcelable(KEY_BROADCAST_METADATA, data);
+        mTestFragment.setArguments(bundle);
+
+        mTestFragment.onAttach(mContext);
+
+        verify(mController).setSourceFromQrCode(eq(data), any());
+        verify(mFeatureFactory.metricsFeatureProvider)
+                .action(
+                        any(),
+                        eq(SettingsEnums.ACTION_AUDIO_STREAM_QR_CODE_SCAN_SUCCEED),
+                        anyInt());
     }
 
     public static class TestFragment extends AudioStreamsDashboardFragment {
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsDialogFragmentTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsDialogFragmentTest.java
index e83dade..efdd389 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsDialogFragmentTest.java
@@ -73,7 +73,7 @@
     }
 
     @Test
-    public void testShowDialog() {
+    public void testShowDialog_dismissAll() {
         FragmentController.setupFragment(mFragment);
         AudioStreamsDialogFragment.show(mFragment, mDialogBuilder, SettingsEnums.PAGE_UNKNOWN);
         ShadowLooper.idleMainLooper();
@@ -81,5 +81,8 @@
         var dialog = ShadowAlertDialog.getLatestAlertDialog();
         assertThat(dialog).isNotNull();
         assertThat(dialog.isShowing()).isTrue();
+
+        AudioStreamsDialogFragment.dismissAll(mFragment);
+        assertThat(dialog.isShowing()).isFalse();
     }
 }
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsHelperTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsHelperTest.java
new file mode 100644
index 0000000..66ef5fb
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsHelperTest.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.connecteddevice.audiosharing.audiostreams;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothLeBroadcastMetadata;
+import android.bluetooth.BluetoothLeBroadcastReceiveState;
+import android.content.Context;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.testutils.shadow.ShadowThreadUtils;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(
+        shadows = {
+            ShadowThreadUtils.class,
+        })
+public class AudioStreamsHelperTest {
+    @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+    private static final int GROUP_ID = 1;
+    private static final int BROADCAST_ID_1 = 1;
+    private static final int BROADCAST_ID_2 = 2;
+    private static final String BROADCAST_NAME = "name";
+    private final Context mContext = spy(ApplicationProvider.getApplicationContext());
+    @Mock private LocalBluetoothManager mLocalBluetoothManager;
+    @Mock private LocalBluetoothProfileManager mLocalBluetoothProfileManager;
+    @Mock private LocalBluetoothLeBroadcastAssistant mAssistant;
+    @Mock private CachedBluetoothDeviceManager mDeviceManager;
+    @Mock private BluetoothLeBroadcastMetadata mMetadata;
+    @Mock private CachedBluetoothDevice mCachedDevice;
+    @Mock private BluetoothDevice mDevice;
+    private AudioStreamsHelper mHelper;
+
+    @Before
+    public void setUp() {
+        when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBluetoothProfileManager);
+        when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mDeviceManager);
+        when(mLocalBluetoothProfileManager.getLeAudioBroadcastAssistantProfile())
+                .thenReturn(mAssistant);
+        mHelper = spy(new AudioStreamsHelper(mLocalBluetoothManager));
+    }
+
+    @Test
+    public void addSource_noDevice_doNothing() {
+        when(mAssistant.getDevicesMatchingConnectionStates(any()))
+                .thenReturn(Collections.emptyList());
+        mHelper.addSource(mMetadata);
+
+        verify(mAssistant, never()).addSource(any(), any(), anyBoolean());
+    }
+
+    @Test
+    public void addSource_hasDevice() {
+        List<BluetoothDevice> devices = new ArrayList<>();
+        devices.add(mDevice);
+        when(mAssistant.getDevicesMatchingConnectionStates(any())).thenReturn(devices);
+        when(mDeviceManager.findDevice(any())).thenReturn(mCachedDevice);
+        when(mCachedDevice.getDevice()).thenReturn(mDevice);
+        when(mCachedDevice.getGroupId()).thenReturn(GROUP_ID);
+
+        mHelper.addSource(mMetadata);
+
+        verify(mAssistant).addSource(eq(mDevice), eq(mMetadata), anyBoolean());
+    }
+
+    @Test
+    public void removeSource_noDevice_doNothing() {
+        when(mAssistant.getDevicesMatchingConnectionStates(any()))
+                .thenReturn(Collections.emptyList());
+        mHelper.removeSource(BROADCAST_ID_1);
+
+        verify(mAssistant, never()).removeSource(any(), anyInt());
+    }
+
+    @Test
+    public void removeSource_noConnectedSource_doNothing() {
+        List<BluetoothDevice> devices = new ArrayList<>();
+        devices.add(mDevice);
+        when(mAssistant.getDevicesMatchingConnectionStates(any())).thenReturn(devices);
+        BluetoothLeBroadcastReceiveState source = mock(BluetoothLeBroadcastReceiveState.class);
+        when(source.getBroadcastId()).thenReturn(BROADCAST_ID_2);
+        when(mDeviceManager.findDevice(any())).thenReturn(mCachedDevice);
+        when(mCachedDevice.getDevice()).thenReturn(mDevice);
+        when(mCachedDevice.getGroupId()).thenReturn(GROUP_ID);
+        when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of(source));
+
+        mHelper.removeSource(BROADCAST_ID_1);
+
+        verify(mAssistant, never()).removeSource(any(), anyInt());
+    }
+
+    @Test
+    public void removeSource_hasConnectedSource() {
+        List<BluetoothDevice> devices = new ArrayList<>();
+        devices.add(mDevice);
+        when(mAssistant.getDevicesMatchingConnectionStates(any())).thenReturn(devices);
+        BluetoothLeBroadcastReceiveState source = mock(BluetoothLeBroadcastReceiveState.class);
+        when(source.getBroadcastId()).thenReturn(BROADCAST_ID_2);
+        when(mDeviceManager.findDevice(any())).thenReturn(mCachedDevice);
+        when(mCachedDevice.getDevice()).thenReturn(mDevice);
+        when(mCachedDevice.getGroupId()).thenReturn(GROUP_ID);
+        when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of(source));
+        List<Long> bisSyncState = new ArrayList<>();
+        bisSyncState.add(1L);
+        when(source.getBisSyncState()).thenReturn(bisSyncState);
+
+        mHelper.removeSource(BROADCAST_ID_2);
+
+        verify(mAssistant).removeSource(eq(mDevice), anyInt());
+    }
+
+    @Test
+    public void removeSource_memberHasConnectedSource() {
+        List<BluetoothDevice> devices = new ArrayList<>();
+        var memberDevice = mock(BluetoothDevice.class);
+        devices.add(mDevice);
+        devices.add(memberDevice);
+        when(mAssistant.getDevicesMatchingConnectionStates(any())).thenReturn(devices);
+        BluetoothLeBroadcastReceiveState source = mock(BluetoothLeBroadcastReceiveState.class);
+        when(source.getBroadcastId()).thenReturn(BROADCAST_ID_2);
+        when(mDeviceManager.findDevice(any())).thenReturn(mCachedDevice);
+        when(mCachedDevice.getDevice()).thenReturn(mDevice);
+        var memberCachedDevice = mock(CachedBluetoothDevice.class);
+        when(memberCachedDevice.getDevice()).thenReturn(memberDevice);
+        when(mCachedDevice.getMemberDevice()).thenReturn(ImmutableSet.of(memberCachedDevice));
+        when(mCachedDevice.getGroupId()).thenReturn(GROUP_ID);
+        when(mAssistant.getAllSources(mDevice)).thenReturn(ImmutableList.of());
+        when(mAssistant.getAllSources(memberDevice)).thenReturn(ImmutableList.of(source));
+        List<Long> bisSyncState = new ArrayList<>();
+        bisSyncState.add(1L);
+        when(source.getBisSyncState()).thenReturn(bisSyncState);
+
+        mHelper.removeSource(BROADCAST_ID_2);
+
+        verify(mAssistant).removeSource(eq(memberDevice), anyInt());
+    }
+
+    @Test
+    public void getAllConnectedSources_noAssistant() {
+        when(mLocalBluetoothProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(null);
+        mHelper = new AudioStreamsHelper(mLocalBluetoothManager);
+
+        assertThat(mHelper.getAllConnectedSources()).isEmpty();
+    }
+
+    @Test
+    public void getAllConnectedSources_returnSource() {
+        List<BluetoothDevice> devices = new ArrayList<>();
+        devices.add(mDevice);
+        when(mAssistant.getDevicesMatchingConnectionStates(any())).thenReturn(devices);
+        BluetoothLeBroadcastReceiveState source = mock(BluetoothLeBroadcastReceiveState.class);
+        when(mDeviceManager.findDevice(any())).thenReturn(mCachedDevice);
+        when(mCachedDevice.getDevice()).thenReturn(mDevice);
+        when(mCachedDevice.getGroupId()).thenReturn(GROUP_ID);
+        when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of(source));
+        List<Long> bisSyncState = new ArrayList<>();
+        bisSyncState.add(1L);
+        when(source.getBisSyncState()).thenReturn(bisSyncState);
+
+        var list = mHelper.getAllConnectedSources();
+        assertThat(list).isNotEmpty();
+        assertThat(list.get(0)).isEqualTo(source);
+    }
+
+    @Test
+    public void startMediaService_noDevice_doNothing() {
+        mHelper.startMediaService(mContext, BROADCAST_ID_1, BROADCAST_NAME);
+
+        verify(mContext, never()).startService(any());
+    }
+
+    @Test
+    public void startMediaService_hasDevice() {
+        List<BluetoothDevice> devices = new ArrayList<>();
+        devices.add(mDevice);
+        when(mAssistant.getDevicesMatchingConnectionStates(any())).thenReturn(devices);
+        BluetoothLeBroadcastReceiveState source = mock(BluetoothLeBroadcastReceiveState.class);
+        when(mDeviceManager.findDevice(any())).thenReturn(mCachedDevice);
+        when(mCachedDevice.getDevice()).thenReturn(mDevice);
+        when(mCachedDevice.getGroupId()).thenReturn(GROUP_ID);
+        when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of(source));
+        List<Long> bisSyncState = new ArrayList<>();
+        bisSyncState.add(1L);
+        when(source.getBisSyncState()).thenReturn(bisSyncState);
+
+        mHelper.startMediaService(mContext, BROADCAST_ID_1, BROADCAST_NAME);
+
+        verify(mContext).startService(any());
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsProgressCategoryControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsProgressCategoryControllerTest.java
index d43ec81..fd1b649 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsProgressCategoryControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsProgressCategoryControllerTest.java
@@ -168,6 +168,25 @@
     }
 
     @Test
+    public void testShowToast_noError() {
+        mController.showToast(BROADCAST_NAME_1);
+    }
+
+    @Test
+    public void testOnStop_unregister() {
+        mController.onStop(mLifecycleOwner);
+
+        verify(mBluetoothEventManager).unregisterCallback(any());
+    }
+
+    @Test
+    public void testGetFragment_returnFragment() {
+        mController.setFragment(mFragment);
+
+        assertThat(mController.getFragment()).isEqualTo(mFragment);
+    }
+
+    @Test
     public void testOnStart_initNoDevice_showDialog() {
         when(mLeBroadcastAssistant.isSearchInProgress()).thenReturn(true);
 
@@ -245,6 +264,25 @@
     }
 
     @Test
+    public void testOnStart_initHasDevice_scanningInProgress() {
+        // Setup a device
+        ShadowAudioStreamsHelper.setCachedBluetoothDeviceInSharingOrLeConnected(mDevice);
+        when(mLeBroadcastAssistant.isSearchInProgress()).thenReturn(true);
+
+        mController.onStart(mLifecycleOwner);
+        shadowOf(Looper.getMainLooper()).idle();
+
+        verify(mLeBroadcastAssistant).registerServiceCallBack(any(), any());
+        verify(mLeBroadcastAssistant).stopSearchingForSources();
+        verify(mLeBroadcastAssistant).startSearchingForSources(any());
+
+        var dialog = ShadowAlertDialog.getLatestAlertDialog();
+        assertThat(dialog).isNull();
+
+        verify(mController, never()).moveToState(any(), any());
+    }
+
+    @Test
     public void testOnStart_handleSourceFromQrCode() {
         // Setup a device
         ShadowAudioStreamsHelper.setCachedBluetoothDeviceInSharingOrLeConnected(mDevice);
@@ -383,6 +421,49 @@
     }
 
     @Test
+    public void testHandleSourceAddRequest_updateMetadataAndState() {
+        // Setup a device
+        ShadowAudioStreamsHelper.setCachedBluetoothDeviceInSharingOrLeConnected(mDevice);
+
+        var metadata =
+                BluetoothLeBroadcastMetadataExt.INSTANCE.convertToBroadcastMetadata(VALID_METADATA);
+        assertThat(metadata).isNotNull();
+        var metadataWithNoCode =
+                new BluetoothLeBroadcastMetadata.Builder(metadata)
+                        .setBroadcastId(NEWLY_FOUND_BROADCAST_ID)
+                        .setBroadcastName(BROADCAST_NAME_1)
+                        .build();
+        // A new source is found
+        mController.handleSourceFound(metadataWithNoCode);
+
+        ArgumentCaptor<AudioStreamPreference> preferenceCaptor =
+                ArgumentCaptor.forClass(AudioStreamPreference.class);
+        ArgumentCaptor<AudioStreamsProgressCategoryController.AudioStreamState> stateCaptor =
+                ArgumentCaptor.forClass(
+                        AudioStreamsProgressCategoryController.AudioStreamState.class);
+
+        // moving state to SYNCED
+        verify(mController).moveToState(preferenceCaptor.capture(), stateCaptor.capture());
+        var preference = preferenceCaptor.getValue();
+        var state = stateCaptor.getValue();
+
+        assertThat(preference).isNotNull();
+        assertThat(preference.getAudioStreamBroadcastId()).isEqualTo(NEWLY_FOUND_BROADCAST_ID);
+        assertThat(state).isEqualTo(SYNCED);
+
+        var updatedMetadata =
+                new BluetoothLeBroadcastMetadata.Builder(metadataWithNoCode)
+                        .setBroadcastCode(BROADCAST_CODE)
+                        .build();
+        mController.handleSourceAddRequest(preference, updatedMetadata);
+        // state updated to ADD_SOURCE_WAIT_FOR_RESPONSE
+        assertThat(preference.getAudioStreamBroadcastId()).isEqualTo(NEWLY_FOUND_BROADCAST_ID);
+        assertThat(preference.getAudioStreamMetadata().getBroadcastCode())
+                .isEqualTo(BROADCAST_CODE);
+        assertThat(preference.getAudioStreamState()).isEqualTo(ADD_SOURCE_WAIT_FOR_RESPONSE);
+    }
+
+    @Test
     public void testHandleSourceFound_sameIdWithSourceFromQrCode_updateMetadataAndState() {
         // Setup a device
         ShadowAudioStreamsHelper.setCachedBluetoothDeviceInSharingOrLeConnected(mDevice);
@@ -519,6 +600,42 @@
     }
 
     @Test
+    public void testHandleSourceLost_sourceConnected_doNothing() {
+        // Setup a device
+        ShadowAudioStreamsHelper.setCachedBluetoothDeviceInSharingOrLeConnected(mDevice);
+
+        // Setup mPreference so it's not null
+        mController.displayPreference(mScreen);
+
+        // A new source found
+        when(mMetadata.getBroadcastId()).thenReturn(NEWLY_FOUND_BROADCAST_ID);
+        mController.handleSourceFound(mMetadata);
+        shadowOf(Looper.getMainLooper()).idle();
+
+        // A new source found is lost, but the source is still connected
+        BluetoothLeBroadcastReceiveState connected = createConnectedMock(NEWLY_FOUND_BROADCAST_ID);
+        when(mAudioStreamsHelper.getAllConnectedSources()).thenReturn(ImmutableList.of(connected));
+        mController.handleSourceLost(NEWLY_FOUND_BROADCAST_ID);
+        shadowOf(Looper.getMainLooper()).idle();
+
+        ArgumentCaptor<AudioStreamPreference> preferenceToAdd =
+                ArgumentCaptor.forClass(AudioStreamPreference.class);
+        ArgumentCaptor<AudioStreamsProgressCategoryController.AudioStreamState> state =
+                ArgumentCaptor.forClass(
+                        AudioStreamsProgressCategoryController.AudioStreamState.class);
+
+        // Verify a new preference is created with state SYNCED.
+        verify(mController).moveToState(preferenceToAdd.capture(), state.capture());
+        assertThat(preferenceToAdd.getValue()).isNotNull();
+        assertThat(preferenceToAdd.getValue().getAudioStreamBroadcastId())
+                .isEqualTo(NEWLY_FOUND_BROADCAST_ID);
+        assertThat(state.getValue()).isEqualTo(SYNCED);
+
+        // No preference is removed.
+        verify(mPreference, never()).removePreference(any());
+    }
+
+    @Test
     public void testHandleSourceRemoved_removed() {
         // Setup a device
         ShadowAudioStreamsHelper.setCachedBluetoothDeviceInSharingOrLeConnected(mDevice);
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsProgressCategoryPreferenceTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsProgressCategoryPreferenceTest.java
index 337d64d..76bd5ec 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsProgressCategoryPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsProgressCategoryPreferenceTest.java
@@ -53,6 +53,8 @@
 
     @Test
     public void addAudioStreamPreference_singlePreference() {
+        mPreference = spy(new AudioStreamsProgressCategoryPreference(mContext, null));
+        when(mPreference.getPreferenceManager()).thenReturn(mPreferenceManager);
         AudioStreamPreference first = new AudioStreamPreference(mContext, null);
         mPreference.addAudioStreamPreference(first, (p1, p2) -> 0);
 
@@ -62,6 +64,8 @@
 
     @Test
     public void addAudioStreamPreference_multiPreference_sorted() {
+        mPreference = spy(new AudioStreamsProgressCategoryPreference(mContext, null, 0));
+        when(mPreference.getPreferenceManager()).thenReturn(mPreferenceManager);
         Comparator<AudioStreamPreference> c =
                 Comparator.comparingInt(AudioStreamPreference::getOrder);
         AudioStreamPreference first = new AudioStreamPreference(mContext, null);
@@ -78,6 +82,8 @@
 
     @Test
     public void removeAudioStreamPreferences_shouldBeEmpty() {
+        mPreference = spy(new AudioStreamsProgressCategoryPreference(mContext, null, 0, 0));
+        when(mPreference.getPreferenceManager()).thenReturn(mPreferenceManager);
         Comparator<AudioStreamPreference> c =
                 Comparator.comparingInt(AudioStreamPreference::getOrder);
         AudioStreamPreference first = new AudioStreamPreference(mContext, null);
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsQrCodeFragmentTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsQrCodeFragmentTest.java
index 7d85b7a..06e4837 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsQrCodeFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsQrCodeFragmentTest.java
@@ -98,6 +98,22 @@
     }
 
     @Test
+    public void onCreateView_noProfile_noQrCode() {
+        when(mBtProfileManager.getLeAudioBroadcastProfile()).thenReturn(null);
+        FragmentController.setupFragment(
+                mFragment, FragmentActivity.class, /* containerViewId= */ 0, /* bundle= */ null);
+        View view = mFragment.getView();
+
+        assertThat(view).isNotNull();
+        ImageView qrCodeView = view.findViewById(R.id.qrcode_view);
+        TextView passwordView = view.requireViewById(R.id.password);
+        assertThat(qrCodeView).isNotNull();
+        assertThat(qrCodeView.getDrawable()).isNull();
+        assertThat(passwordView).isNotNull();
+        assertThat(passwordView.getText().toString()).isEqualTo("");
+    }
+
+    @Test
     public void onCreateView_noMetadata_noQrCode() {
         List<BluetoothLeBroadcastMetadata> list = new ArrayList<>();
         when(mBroadcast.getAllBroadcastMetadata()).thenReturn(list);
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/testshadows/ShadowAudioStreamsHelper.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/testshadows/ShadowAudioStreamsHelper.java
index 13c19ca..051eda7 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/testshadows/ShadowAudioStreamsHelper.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/testshadows/ShadowAudioStreamsHelper.java
@@ -16,6 +16,7 @@
 
 package com.android.settings.connecteddevice.audiosharing.audiostreams.testshadows;
 
+import android.bluetooth.BluetoothLeBroadcastMetadata;
 import android.bluetooth.BluetoothLeBroadcastReceiveState;
 
 import androidx.annotation.Nullable;
@@ -69,4 +70,16 @@
     public LocalBluetoothLeBroadcastAssistant getLeBroadcastAssistant() {
         return sMockHelper.getLeBroadcastAssistant();
     }
+
+    /** Removes sources from LE broadcasts associated for all active sinks based on broadcast Id. */
+    @Implementation
+    public void removeSource(int broadcastId) {
+        sMockHelper.removeSource(broadcastId);
+    }
+
+    /** Adds the specified LE broadcast source to all active sinks. */
+    @Implementation
+    public void addSource(BluetoothLeBroadcastMetadata source) {
+        sMockHelper.addSource(source);
+    }
 }