diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 724ff89725abf..9b3f1a8f0734d 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -350,6 +350,7 @@
+
startSwitchBroadcast());
changeOutput.setOnClickListener((view) -> {
mMediaOutputDialogFactory.create(mOutputPackageName, true, null);
dismiss();
@@ -101,6 +199,79 @@ public class BroadcastDialog extends SystemUIDialog {
});
}
+ @Override
+ public void onStop() {
+ super.onStop();
+ unregisterBroadcastCallBack(mBroadcastCallback);
+ }
+
+ void refreshSwitchBroadcastButton() {
+ String switchBroadcastApp = MediaDataUtils.getAppLabel(mContext, mOutputPackageName,
+ mContext.getString(R.string.bt_le_audio_broadcast_dialog_unknown_name));
+ mSwitchBroadcast.setText(mContext.getString(
+ R.string.bt_le_audio_broadcast_dialog_switch_app, switchBroadcastApp), null);
+ mSwitchBroadcast.setEnabled(true);
+ }
+
+ private void startSwitchBroadcast() {
+ if (DEBUG) {
+ Log.d(TAG, "startSwitchBroadcast");
+ }
+ mSwitchBroadcast.setText(R.string.media_output_broadcast_starting);
+ mSwitchBroadcast.setEnabled(false);
+ //Stop the current Broadcast
+ if (!stopBluetoothLeBroadcast()) {
+ handleLeBroadcastStopFailed();
+ return;
+ }
+ }
+
+ private void registerBroadcastCallBack(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull BluetoothLeBroadcast.Callback callback) {
+ LocalBluetoothLeBroadcast broadcast =
+ mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile();
+ if (broadcast == null) {
+ Log.d(TAG, "The broadcast profile is null");
+ return;
+ }
+ broadcast.registerServiceCallBack(executor, callback);
+ }
+
+ private void unregisterBroadcastCallBack(@NonNull BluetoothLeBroadcast.Callback callback) {
+ LocalBluetoothLeBroadcast broadcast =
+ mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile();
+ if (broadcast == null) {
+ Log.d(TAG, "The broadcast profile is null");
+ return;
+ }
+ broadcast.unregisterServiceCallBack(callback);
+ }
+
+ boolean startBluetoothLeBroadcast() {
+ LocalBluetoothLeBroadcast broadcast =
+ mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile();
+ if (broadcast == null) {
+ Log.d(TAG, "The broadcast profile is null");
+ return false;
+ }
+ String switchBroadcastApp = MediaDataUtils.getAppLabel(mContext, mOutputPackageName,
+ mContext.getString(R.string.bt_le_audio_broadcast_dialog_unknown_name));
+ broadcast.startBroadcast(switchBroadcastApp, /*language*/ null);
+ return true;
+ }
+
+ boolean stopBluetoothLeBroadcast() {
+ LocalBluetoothLeBroadcast broadcast =
+ mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile();
+ if (broadcast == null) {
+ Log.d(TAG, "The broadcast profile is null");
+ return false;
+ }
+ broadcast.stopLatestBroadcast();
+ return true;
+ }
+
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
@@ -125,4 +296,45 @@ public class BroadcastDialog extends SystemUIDialog {
}
}
+ void handleLeBroadcastStarted() {
+ // Waiting for the onBroadcastMetadataChanged. The UI launchs the broadcast dialog when
+ // the metadata is ready.
+ mShouldLaunchLeBroadcastDialog = true;
+ }
+
+ private void handleLeBroadcastStartFailed() {
+ mSwitchBroadcast.setText(R.string.media_output_broadcast_start_failed);
+ mSwitchBroadcast.setEnabled(false);
+ refreshSwitchBroadcastButton();
+ }
+
+ void handleLeBroadcastMetadataChanged() {
+ if (mShouldLaunchLeBroadcastDialog) {
+ startLeBroadcastDialog();
+ mShouldLaunchLeBroadcastDialog = false;
+ }
+ }
+
+ @VisibleForTesting
+ void handleLeBroadcastStopped() {
+ mShouldLaunchLeBroadcastDialog = false;
+ if (!startBluetoothLeBroadcast()) {
+ handleLeBroadcastStartFailed();
+ return;
+ }
+ }
+
+ private void handleLeBroadcastStopFailed() {
+ mSwitchBroadcast.setText(R.string.media_output_broadcast_start_failed);
+ mSwitchBroadcast.setEnabled(false);
+ refreshSwitchBroadcastButton();
+ }
+
+ private void startLeBroadcastDialog() {
+ mBroadcastSender.sendBroadcast(new Intent()
+ .setPackage(mContext.getPackageName())
+ .setAction(MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG)
+ .putExtra(MediaOutputConstants.EXTRA_PACKAGE_NAME, mOutputPackageName));
+ dismiss();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialogController.java b/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialogController.java
index 1b699e8ea5dda..17bf1a716944d 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialogController.java
@@ -16,11 +16,14 @@
package com.android.systemui.bluetooth;
+import android.annotation.Nullable;
import android.content.Context;
import android.view.View;
import com.android.internal.logging.UiEventLogger;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.systemui.animation.DialogLaunchAnimator;
+import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.media.dialog.MediaOutputDialogFactory;
@@ -36,15 +39,21 @@ public class BroadcastDialogController {
private UiEventLogger mUiEventLogger;
private DialogLaunchAnimator mDialogLaunchAnimator;
private MediaOutputDialogFactory mMediaOutputDialogFactory;
+ private final LocalBluetoothManager mLocalBluetoothManager;
+ private BroadcastSender mBroadcastSender;
@Inject
public BroadcastDialogController(Context context, UiEventLogger uiEventLogger,
DialogLaunchAnimator dialogLaunchAnimator,
- MediaOutputDialogFactory mediaOutputDialogFactory) {
+ MediaOutputDialogFactory mediaOutputDialogFactory,
+ @Nullable LocalBluetoothManager localBluetoothManager,
+ BroadcastSender broadcastSender) {
mContext = context;
mUiEventLogger = uiEventLogger;
mDialogLaunchAnimator = dialogLaunchAnimator;
mMediaOutputDialogFactory = mediaOutputDialogFactory;
+ mLocalBluetoothManager = localBluetoothManager;
+ mBroadcastSender = broadcastSender;
}
/** Creates a [BroadcastDialog] for the user to switch broadcast or change the output device
@@ -55,7 +64,8 @@ public class BroadcastDialogController {
public void createBroadcastDialog(String currentBroadcastAppName, String outputPkgName,
boolean aboveStatusBar, View view) {
BroadcastDialog broadcastDialog = new BroadcastDialog(mContext, mMediaOutputDialogFactory,
- currentBroadcastAppName, outputPkgName, mUiEventLogger);
+ mLocalBluetoothManager, currentBroadcastAppName, outputPkgName, mUiEventLogger,
+ mBroadcastSender);
if (view != null) {
mDialogLaunchAnimator.showFromView(broadcastDialog, view);
} else {
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 2aedd36346262..84dc2851b56c9 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -996,7 +996,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
mAudioManager, mPowerExemptionManager, mKeyGuardManager, mFeatureFlags);
MediaOutputBroadcastDialog dialog = new MediaOutputBroadcastDialog(mContext, true,
broadcastSender, controller);
- mDialogLaunchAnimator.showFromView(dialog, mediaOutputDialog);
+ dialog.show();
}
String getBroadcastName() {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogReceiver.kt
index 760a42cc512c3..132bf99c3f627 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogReceiver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogReceiver.kt
@@ -62,7 +62,8 @@ class MediaOutputDialogReceiver @Inject constructor(
private fun launchMediaOutputBroadcastDialogIfPossible(packageName: String?) {
if (!packageName.isNullOrEmpty()) {
- mediaOutputBroadcastDialogFactory.create(packageName, false)
+ mediaOutputBroadcastDialogFactory.create(
+ packageName, aboveStatusBar = true, view = null)
} else if (DEBUG) {
Log.e(TAG, "Unable to launch media output broadcast dialog. Package name is empty.")
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogTest.java
index 9d16185e75c54..6fa19162b1505 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogTest.java
@@ -18,7 +18,11 @@ package com.android.systemui.bluetooth;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -29,7 +33,11 @@ import android.widget.TextView;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.UiEventLogger;
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.media.dialog.MediaOutputDialogFactory;
@@ -47,6 +55,12 @@ public class BroadcastDialogTest extends SysuiTestCase {
private static final String CURRENT_BROADCAST_APP = "Music";
private static final String SWITCH_APP = "System UI";
private static final String TEST_PACKAGE = "com.android.systemui";
+ private final LocalBluetoothManager mLocalBluetoothManager = mock(LocalBluetoothManager.class);
+ private final LocalBluetoothProfileManager mLocalBluetoothProfileManager = mock(
+ LocalBluetoothProfileManager.class);
+ private final LocalBluetoothLeBroadcast mLocalBluetoothLeBroadcast = mock(
+ LocalBluetoothLeBroadcast.class);
+ private final BroadcastSender mBroadcastSender = mock(BroadcastSender.class);
private BroadcastDialog mBroadcastDialog;
private View mDialogView;
private TextView mTitle;
@@ -57,9 +71,11 @@ public class BroadcastDialogTest extends SysuiTestCase {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBluetoothProfileManager);
+ when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(null);
mBroadcastDialog = new BroadcastDialog(mContext, mock(MediaOutputDialogFactory.class),
- CURRENT_BROADCAST_APP, TEST_PACKAGE, mock(UiEventLogger.class));
-
+ mLocalBluetoothManager, CURRENT_BROADCAST_APP, TEST_PACKAGE,
+ mock(UiEventLogger.class), mBroadcastSender);
mBroadcastDialog.show();
mDialogView = mBroadcastDialog.mDialogView;
}
@@ -100,4 +116,61 @@ public class BroadcastDialogTest extends SysuiTestCase {
assertThat(mBroadcastDialog.isShowing()).isFalse();
}
+
+ @Test
+ public void onClick_withSwitchBroadcast_stopCurrentBroadcast() {
+ when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
+ mLocalBluetoothLeBroadcast);
+ mSwitchBroadcastAppButton = mDialogView.requireViewById(R.id.switch_broadcast);
+ mSwitchBroadcastAppButton.performClick();
+
+ verify(mLocalBluetoothLeBroadcast).stopLatestBroadcast();
+ }
+
+ @Test
+ public void onClick_withSwitchBroadcast_stopCurrentBroadcastFailed() {
+ mSwitchBroadcastAppButton = mDialogView.requireViewById(R.id.switch_broadcast);
+ mSwitchBroadcastAppButton.performClick();
+
+ assertThat(mSwitchBroadcastAppButton.getText().toString()).isEqualTo(
+ mContext.getString(R.string.bt_le_audio_broadcast_dialog_switch_app, SWITCH_APP));
+ }
+
+ @Test
+ public void handleLeBroadcastStopped_withBroadcastProfileNull_doRefreshButton() {
+ when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(null);
+ mSwitchBroadcastAppButton = mDialogView.requireViewById(R.id.switch_broadcast);
+
+ mBroadcastDialog.handleLeBroadcastStopped();
+
+ assertThat(mSwitchBroadcastAppButton.getText().toString()).isEqualTo(
+ mContext.getString(R.string.bt_le_audio_broadcast_dialog_switch_app, SWITCH_APP));
+ }
+
+ @Test
+ public void handleLeBroadcastStopped_withBroadcastProfile_doStartBroadcast() {
+ when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
+ mLocalBluetoothLeBroadcast);
+
+ mBroadcastDialog.handleLeBroadcastStopped();
+
+ verify(mLocalBluetoothLeBroadcast).startBroadcast(eq(SWITCH_APP), any());
+ }
+
+ @Test
+ public void handleLeBroadcastMetadataChanged_withNotLaunchFlag_doNotDismissDialog() {
+
+ mBroadcastDialog.handleLeBroadcastMetadataChanged();
+
+ assertThat(mBroadcastDialog.isShowing()).isTrue();
+ }
+
+ @Test
+ public void handleLeBroadcastMetadataChanged_withLaunchFlag_dismissDialog() {
+
+ mBroadcastDialog.handleLeBroadcastStarted();
+ mBroadcastDialog.handleLeBroadcastMetadataChanged();
+
+ assertThat(mBroadcastDialog.isShowing()).isFalse();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogReceiverTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogReceiverTest.java
index 3d5dba3b9efcd..e2cf87a6dd621 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogReceiverTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogReceiverTest.java
@@ -92,7 +92,7 @@ public class MediaOutputDialogReceiverTest extends SysuiTestCase {
verify(mMockMediaOutputDialogFactory, never()).create(any(), anyBoolean(), any());
verify(mMockMediaOutputBroadcastDialogFactory, times(1))
- .create(getContext().getPackageName(), false, null);
+ .create(getContext().getPackageName(), true, null);
}
@Test