From ad708d4d93592ec9e3051901c214bf3910ac9f78 Mon Sep 17 00:00:00 2001 From: SongFerngWang Date: Wed, 14 Sep 2022 16:04:16 +0800 Subject: [PATCH] [LE Broadcast] Add the active LE device into broadcast when broadcasting - Add the source into active sink device when user start the broadcasting. - Add a flag to avoid re-register callback of broadcast. - Register/Unregister the assistant's callback. Bug: 246761387 Test: local test Test: atest MediaOutputBroadcastDialogTest Change-Id: I7326a3d299943de2ede144f12d2b663c915dd304 --- .../media/dialog/MediaOutputBaseDialog.java | 16 +- .../dialog/MediaOutputBroadcastDialog.java | 152 +++++++++++++- .../media/dialog/MediaOutputController.java | 73 ++++++- .../MediaOutputBroadcastDialogTest.java | 195 ++++++++++++++++++ 4 files changed, 424 insertions(+), 12 deletions(-) create mode 100644 packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogTest.java diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java index 35819e30fe450..9606bcf3fd9b2 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java @@ -78,7 +78,7 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements private static final boolean DEBUG = true; private static final int HANDLE_BROADCAST_FAILED_DELAY = 3000; - private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper()); + protected final Handler mMainThreadHandler = new Handler(Looper.getMainLooper()); private final RecyclerView.LayoutManager mLayoutManager; final Context mContext; @@ -102,11 +102,13 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements private int mListMaxHeight; private int mItemHeight; private WallpaperColors mWallpaperColors; - private Executor mExecutor; private boolean mShouldLaunchLeBroadcastDialog; + private boolean mIsLeBroadcastCallbackRegistered; MediaOutputBaseAdapter mAdapter; + protected Executor mExecutor; + private final ViewTreeObserver.OnGlobalLayoutListener mDeviceListLayoutListener = () -> { ViewGroup.LayoutParams params = mDeviceListLayout.getLayoutParams(); int totalItemsHeight = mAdapter.getItemCount() * mItemHeight; @@ -274,17 +276,19 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements public void onStart() { super.onStart(); mMediaOutputController.start(this); - if(isBroadcastSupported()) { - mMediaOutputController.registerLeBroadcastServiceCallBack(mExecutor, + if (isBroadcastSupported() && !mIsLeBroadcastCallbackRegistered) { + mMediaOutputController.registerLeBroadcastServiceCallback(mExecutor, mBroadcastCallback); + mIsLeBroadcastCallbackRegistered = true; } } @Override public void onStop() { super.onStop(); - if(isBroadcastSupported()) { - mMediaOutputController.unregisterLeBroadcastServiceCallBack(mBroadcastCallback); + if (isBroadcastSupported() && mIsLeBroadcastCallbackRegistered) { + mMediaOutputController.unregisterLeBroadcastServiceCallback(mBroadcastCallback); + mIsLeBroadcastCallbackRegistered = false; } mMediaOutputController.stop(); } diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java index 12d6b7ccf5cd0..f0ff1409faf1c 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java @@ -17,6 +17,10 @@ package com.android.systemui.media.dialog; import android.app.AlertDialog; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothLeBroadcastAssistant; +import android.bluetooth.BluetoothLeBroadcastMetadata; +import android.bluetooth.BluetoothLeBroadcastReceiveState; import android.content.Context; import android.graphics.Bitmap; import android.os.Bundle; @@ -34,8 +38,11 @@ import android.widget.EditText; import android.widget.ImageView; import android.widget.TextView; +import androidx.annotation.NonNull; import androidx.core.graphics.drawable.IconCompat; +import com.android.settingslib.media.BluetoothMediaDevice; +import com.android.settingslib.media.MediaDevice; import com.android.settingslib.qrcode.QrCodeGenerator; import com.android.systemui.R; import com.android.systemui.broadcast.BroadcastSender; @@ -49,7 +56,7 @@ import com.google.zxing.WriterException; */ @SysUISingleton public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog { - private static final String TAG = "BroadcastDialog"; + private static final String TAG = "MediaOutputBroadcastDialog"; private ViewStub mBroadcastInfoArea; private ImageView mBroadcastQrCodeView; @@ -66,6 +73,7 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog { private String mCurrentBroadcastName; private String mCurrentBroadcastCode; private boolean mIsStopbyUpdateBroadcastCode = false; + private TextWatcher mTextWatcher = new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { @@ -105,6 +113,79 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog { } }; + private boolean mIsLeBroadcastAssistantCallbackRegistered; + + private BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback = + new BluetoothLeBroadcastAssistant.Callback() { + @Override + public void onSearchStarted(int reason) { + Log.d(TAG, "Assistant-onSearchStarted: " + reason); + } + + @Override + public void onSearchStartFailed(int reason) { + Log.d(TAG, "Assistant-onSearchStartFailed: " + reason); + } + + @Override + public void onSearchStopped(int reason) { + Log.d(TAG, "Assistant-onSearchStopped: " + reason); + } + + @Override + public void onSearchStopFailed(int reason) { + Log.d(TAG, "Assistant-onSearchStopFailed: " + reason); + } + + @Override + public void onSourceFound(@NonNull BluetoothLeBroadcastMetadata source) { + Log.d(TAG, "Assistant-onSourceFound:"); + } + + @Override + public void onSourceAdded(@NonNull BluetoothDevice sink, int sourceId, int reason) { + Log.d(TAG, "Assistant-onSourceAdded: Device: " + sink + + ", sourceId: " + sourceId); + mMainThreadHandler.post(() -> refreshUi()); + } + + @Override + public void onSourceAddFailed(@NonNull BluetoothDevice sink, + @NonNull BluetoothLeBroadcastMetadata source, int reason) { + Log.d(TAG, "Assistant-onSourceAddFailed: Device: " + sink); + } + + @Override + public void onSourceModified(@NonNull BluetoothDevice sink, int sourceId, + int reason) { + Log.d(TAG, "Assistant-onSourceModified:"); + } + + @Override + public void onSourceModifyFailed(@NonNull BluetoothDevice sink, int sourceId, + int reason) { + Log.d(TAG, "Assistant-onSourceModifyFailed:"); + } + + @Override + public void onSourceRemoved(@NonNull BluetoothDevice sink, int sourceId, + int reason) { + Log.d(TAG, "Assistant-onSourceRemoved:"); + } + + @Override + public void onSourceRemoveFailed(@NonNull BluetoothDevice sink, int sourceId, + int reason) { + Log.d(TAG, "Assistant-onSourceRemoveFailed:"); + } + + @Override + public void onReceiveStateChanged(@NonNull BluetoothDevice sink, int sourceId, + @NonNull BluetoothLeBroadcastReceiveState state) { + Log.d(TAG, "Assistant-onReceiveStateChanged:"); + } + }; + static final int METADATA_BROADCAST_NAME = 0; static final int METADATA_BROADCAST_CODE = 1; @@ -130,6 +211,27 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog { initBtQrCodeUI(); } + @Override + public void onStart() { + super.onStart(); + if (!mIsLeBroadcastAssistantCallbackRegistered) { + mIsLeBroadcastAssistantCallbackRegistered = true; + mMediaOutputController.registerLeBroadcastAssistantServiceCallback(mExecutor, + mBroadcastAssistantCallback); + } + connectBroadcastWithActiveDevice(); + } + + @Override + public void onStop() { + super.onStop(); + if (mIsLeBroadcastAssistantCallbackRegistered) { + mIsLeBroadcastAssistantCallbackRegistered = false; + mMediaOutputController.unregisterLeBroadcastAssistantServiceCallback( + mBroadcastAssistantCallback); + } + } + @Override int getHeaderIconRes() { return 0; @@ -224,6 +326,7 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog { mCurrentBroadcastCode = getBroadcastMetadataInfo(METADATA_BROADCAST_CODE); mBroadcastName.setText(mCurrentBroadcastName); mBroadcastCode.setText(mCurrentBroadcastCode); + refresh(false); } private void inflateBroadcastInfoArea() { @@ -233,7 +336,7 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog { private void setQrCodeView() { //get the Metadata, and convert to BT QR code format. - String broadcastMetadata = getBroadcastMetadata(); + String broadcastMetadata = getLocalBroadcastMetadataQrCodeString(); if (broadcastMetadata.isEmpty()) { //TDOD(b/226708424) Error handling for unable to generate the QR code bitmap return; @@ -249,6 +352,33 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog { } } + void connectBroadcastWithActiveDevice() { + //get the Metadata, and convert to BT QR code format. + BluetoothLeBroadcastMetadata broadcastMetadata = getBroadcastMetadata(); + if (broadcastMetadata == null) { + Log.e(TAG, "Error: There is no broadcastMetadata."); + return; + } + MediaDevice mediaDevice = mMediaOutputController.getCurrentConnectedMediaDevice(); + if (mediaDevice == null || !(mediaDevice instanceof BluetoothMediaDevice) + || !mediaDevice.isBLEDevice()) { + Log.e(TAG, "Error: There is no active BT LE device."); + return; + } + BluetoothDevice sink = ((BluetoothMediaDevice) mediaDevice).getCachedDevice().getDevice(); + Log.d(TAG, "The broadcastMetadata broadcastId: " + broadcastMetadata.getBroadcastId() + + ", the device: " + sink.getAnonymizedAddress()); + + if (mMediaOutputController.isThereAnyBroadcastSourceIntoSinkDevice(sink)) { + Log.d(TAG, "The sink device has the broadcast source now."); + return; + } + if (!mMediaOutputController.addSourceIntoSinkDeviceWithBluetoothLeAssistant(sink, + broadcastMetadata, /*isGroupOp=*/ true)) { + Log.e(TAG, "Error: Source add failed"); + } + } + private void updateBroadcastCodeVisibility() { mBroadcastCode.setTransformationMethod( mIsPasswordHide ? HideReturnsTransformationMethod.getInstance() @@ -282,7 +412,11 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog { mAlertDialog.show(); } - private String getBroadcastMetadata() { + private String getLocalBroadcastMetadataQrCodeString() { + return mMediaOutputController.getLocalBroadcastMetadataQrCodeString(); + } + + private BluetoothLeBroadcastMetadata getBroadcastMetadata() { return mMediaOutputController.getBroadcastMetadata(); } @@ -313,6 +447,17 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog { } } + @Override + public boolean isBroadcastSupported() { + boolean isBluetoothLeDevice = false; + if (mMediaOutputController.getCurrentConnectedMediaDevice() != null) { + isBluetoothLeDevice = mMediaOutputController.isBluetoothLeDevice( + mMediaOutputController.getCurrentConnectedMediaDevice()); + } + + return mMediaOutputController.isBroadcastSupported() && isBluetoothLeDevice; + } + @Override public void handleLeBroadcastStarted() { mRetryCount = 0; @@ -332,6 +477,7 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog { @Override public void handleLeBroadcastMetadataChanged() { + Log.d(TAG, "handleLeBroadcastMetadataChanged:"); refreshUi(); } diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java index 84dc2851b56c9..5f49c20bcd0fb 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java @@ -25,7 +25,11 @@ import android.app.AlertDialog; import android.app.KeyguardManager; import android.app.Notification; import android.app.WallpaperColors; +import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothLeBroadcast; +import android.bluetooth.BluetoothLeBroadcastAssistant; +import android.bluetooth.BluetoothLeBroadcastMetadata; +import android.bluetooth.BluetoothLeBroadcastReceiveState; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; @@ -66,6 +70,7 @@ import com.android.settingslib.RestrictedLockUtilsInternal; import com.android.settingslib.Utils; import com.android.settingslib.bluetooth.BluetoothUtils; import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast; +import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant; import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastMetadata; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.media.InfoMediaManager; @@ -1050,7 +1055,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback, ALLOWLIST_DURATION_MS); } - String getBroadcastMetadata() { + String getLocalBroadcastMetadataQrCodeString() { LocalBluetoothLeBroadcast broadcast = mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile(); if (broadcast == null) { @@ -1062,6 +1067,17 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback, return metadata != null ? metadata.convertToQrCodeString() : ""; } + BluetoothLeBroadcastMetadata getBroadcastMetadata() { + LocalBluetoothLeBroadcast broadcast = + mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile(); + if (broadcast == null) { + Log.d(TAG, "getBroadcastMetadata: LE Audio Broadcast is null"); + return null; + } + + return broadcast.getLatestBluetoothLeBroadcastMetadata(); + } + boolean isActiveRemoteDevice(@NonNull MediaDevice device) { final List features = device.getFeatures(); return (features.contains(MediaRoute2Info.FEATURE_REMOTE_PLAYBACK) @@ -1122,7 +1138,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback, return true; } - void registerLeBroadcastServiceCallBack( + void registerLeBroadcastServiceCallback( @NonNull @CallbackExecutor Executor executor, @NonNull BluetoothLeBroadcast.Callback callback) { LocalBluetoothLeBroadcast broadcast = @@ -1131,10 +1147,11 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback, Log.d(TAG, "The broadcast profile is null"); return; } + Log.d(TAG, "Register LE broadcast callback"); broadcast.registerServiceCallBack(executor, callback); } - void unregisterLeBroadcastServiceCallBack( + void unregisterLeBroadcastServiceCallback( @NonNull BluetoothLeBroadcast.Callback callback) { LocalBluetoothLeBroadcast broadcast = mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile(); @@ -1142,9 +1159,59 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback, Log.d(TAG, "The broadcast profile is null"); return; } + Log.d(TAG, "Unregister LE broadcast callback"); broadcast.unregisterServiceCallBack(callback); } + boolean isThereAnyBroadcastSourceIntoSinkDevice(BluetoothDevice sink) { + LocalBluetoothLeBroadcastAssistant assistant = + mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastAssistantProfile(); + if (assistant == null) { + Log.d(TAG, "The broadcast assistant profile is null"); + return false; + } + List sourceList = assistant.getAllSources(sink); + Log.d(TAG, "isThereAnyBroadcastSourceIntoSinkDevice: List size: " + sourceList.size()); + return !sourceList.isEmpty(); + } + + boolean addSourceIntoSinkDeviceWithBluetoothLeAssistant(BluetoothDevice sink, + BluetoothLeBroadcastMetadata metadata, boolean isGroupOp) { + LocalBluetoothLeBroadcastAssistant assistant = + mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastAssistantProfile(); + if (assistant == null) { + Log.d(TAG, "The broadcast assistant profile is null"); + return false; + } + assistant.addSource(sink, metadata, isGroupOp); + return true; + } + + void registerLeBroadcastAssistantServiceCallback( + @NonNull @CallbackExecutor Executor executor, + @NonNull BluetoothLeBroadcastAssistant.Callback callback) { + LocalBluetoothLeBroadcastAssistant assistant = + mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastAssistantProfile(); + if (assistant == null) { + Log.d(TAG, "The broadcast assistant profile is null"); + return; + } + Log.d(TAG, "Register LE broadcast assistant callback"); + assistant.registerServiceCallBack(executor, callback); + } + + void unregisterLeBroadcastAssistantServiceCallback( + @NonNull BluetoothLeBroadcastAssistant.Callback callback) { + LocalBluetoothLeBroadcastAssistant assistant = + mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastAssistantProfile(); + if (assistant == null) { + Log.d(TAG, "The broadcast assistant profile is null"); + return; + } + Log.d(TAG, "Unregister LE broadcast assistant callback"); + assistant.unregisterServiceCallBack(callback); + } + private boolean isPlayBackInfoLocal() { return mMediaController != null && mMediaController.getPlaybackInfo() != null diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogTest.java new file mode 100644 index 0000000000000..891a6f8a102cb --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogTest.java @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2023 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.systemui.media.dialog; + +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyBoolean; +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.KeyguardManager; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothLeBroadcastMetadata; +import android.bluetooth.BluetoothLeBroadcastReceiveState; +import android.media.AudioManager; +import android.media.session.MediaSessionManager; +import android.os.PowerExemptionManager; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import androidx.test.filters.SmallTest; + +import com.android.settingslib.bluetooth.CachedBluetoothDevice; +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.media.BluetoothMediaDevice; +import com.android.settingslib.media.LocalMediaManager; +import com.android.settingslib.media.MediaDevice; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.animation.DialogLaunchAnimator; +import com.android.systemui.broadcast.BroadcastSender; +import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.media.nearby.NearbyMediaDevicesManager; +import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class MediaOutputBroadcastDialogTest extends SysuiTestCase { + + private static final String TEST_PACKAGE = "test_package"; + + // Mock + private final MediaSessionManager mMediaSessionManager = mock(MediaSessionManager.class); + private final LocalBluetoothManager mLocalBluetoothManager = mock(LocalBluetoothManager.class); + private final LocalBluetoothProfileManager mLocalBluetoothProfileManager = mock( + LocalBluetoothProfileManager.class); + private final LocalBluetoothLeBroadcast mLocalBluetoothLeBroadcast = mock( + LocalBluetoothLeBroadcast.class); + private final LocalBluetoothLeBroadcastAssistant mLocalBluetoothLeBroadcastAssistant = mock( + LocalBluetoothLeBroadcastAssistant.class); + private final BluetoothLeBroadcastMetadata mBluetoothLeBroadcastMetadata = mock( + BluetoothLeBroadcastMetadata.class); + private final BluetoothLeBroadcastReceiveState mBluetoothLeBroadcastReceiveState = mock( + BluetoothLeBroadcastReceiveState.class); + private final ActivityStarter mStarter = mock(ActivityStarter.class); + private final BroadcastSender mBroadcastSender = mock(BroadcastSender.class); + private final LocalMediaManager mLocalMediaManager = mock(LocalMediaManager.class); + private final MediaDevice mBluetoothMediaDevice = mock(BluetoothMediaDevice.class); + private final BluetoothDevice mBluetoothDevice = mock(BluetoothDevice.class); + private final CachedBluetoothDevice mCachedBluetoothDevice = mock(CachedBluetoothDevice.class); + private final CommonNotifCollection mNotifCollection = mock(CommonNotifCollection.class); + private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class); + private final NearbyMediaDevicesManager mNearbyMediaDevicesManager = mock( + NearbyMediaDevicesManager.class); + private final AudioManager mAudioManager = mock(AudioManager.class); + private PowerExemptionManager mPowerExemptionManager = mock(PowerExemptionManager.class); + private KeyguardManager mKeyguardManager = mock(KeyguardManager.class); + private FeatureFlags mFlags = mock(FeatureFlags.class); + + private MediaOutputBroadcastDialog mMediaOutputBroadcastDialog; + private MediaOutputController mMediaOutputController; + + @Before + public void setUp() { + when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBluetoothProfileManager); + when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(null); + when(mLocalBluetoothProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(null); + + mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, + mMediaSessionManager, mLocalBluetoothManager, mStarter, + mNotifCollection, mDialogLaunchAnimator, + Optional.of(mNearbyMediaDevicesManager), mAudioManager, mPowerExemptionManager, + mKeyguardManager, mFlags); + mMediaOutputController.mLocalMediaManager = mLocalMediaManager; + mMediaOutputBroadcastDialog = new MediaOutputBroadcastDialog(mContext, false, + mBroadcastSender, mMediaOutputController); + mMediaOutputBroadcastDialog.show(); + } + + @After + public void tearDown() { + mMediaOutputBroadcastDialog.dismissDialog(); + } + + @Test + public void connectBroadcastWithActiveDevice_noBroadcastMetadata_failToAddSource() { + when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn( + mLocalBluetoothLeBroadcast); + when(mLocalBluetoothLeBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(null); + when(mLocalBluetoothProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn( + mLocalBluetoothLeBroadcastAssistant); + + mMediaOutputBroadcastDialog.connectBroadcastWithActiveDevice(); + + verify(mLocalBluetoothLeBroadcastAssistant, never()).addSource(any(), any(), anyBoolean()); + } + + @Test + public void connectBroadcastWithActiveDevice_noConnectedMediaDevice_failToAddSource() { + when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn( + mLocalBluetoothLeBroadcast); + when(mLocalBluetoothLeBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn( + mBluetoothLeBroadcastMetadata); + when(mLocalBluetoothProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn( + mLocalBluetoothLeBroadcastAssistant); + when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(null); + + mMediaOutputBroadcastDialog.connectBroadcastWithActiveDevice(); + + verify(mLocalBluetoothLeBroadcastAssistant, never()).addSource(any(), any(), anyBoolean()); + } + + @Test + public void connectBroadcastWithActiveDevice_hasBroadcastSource_failToAddSource() { + when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn( + mLocalBluetoothLeBroadcast); + when(mLocalBluetoothLeBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn( + mBluetoothLeBroadcastMetadata); + when(mLocalBluetoothProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn( + mLocalBluetoothLeBroadcastAssistant); + when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mBluetoothMediaDevice); + when(((BluetoothMediaDevice) mBluetoothMediaDevice).getCachedDevice()) + .thenReturn(mCachedBluetoothDevice); + when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice); + List sourceList = new ArrayList<>(); + sourceList.add(mBluetoothLeBroadcastReceiveState); + when(mLocalBluetoothLeBroadcastAssistant.getAllSources(mBluetoothDevice)).thenReturn( + sourceList); + + mMediaOutputBroadcastDialog.connectBroadcastWithActiveDevice(); + + verify(mLocalBluetoothLeBroadcastAssistant, never()).addSource(any(), any(), anyBoolean()); + } + + @Test + public void connectBroadcastWithActiveDevice_noBroadcastSource_failToAddSource() { + when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn( + mLocalBluetoothLeBroadcast); + when(mLocalBluetoothProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn( + mLocalBluetoothLeBroadcastAssistant); + when(mLocalBluetoothLeBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn( + mBluetoothLeBroadcastMetadata); + when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mBluetoothMediaDevice); + when(mBluetoothMediaDevice.isBLEDevice()).thenReturn(true); + when(((BluetoothMediaDevice) mBluetoothMediaDevice).getCachedDevice()).thenReturn( + mCachedBluetoothDevice); + when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice); + List sourceList = new ArrayList<>(); + when(mLocalBluetoothLeBroadcastAssistant.getAllSources(mBluetoothDevice)).thenReturn( + sourceList); + + mMediaOutputBroadcastDialog.connectBroadcastWithActiveDevice(); + + verify(mLocalBluetoothLeBroadcastAssistant, times(1)).addSource(any(), any(), anyBoolean()); + } +}