[LE_Broadcast]Start broadcast and stop broadcast

- Add start broadcast UI and stop broadcast UI
- Add broadcast start process
- Add broadcast stop process

Bug: 227511707
Test: build pass and manaual test.
atest MediaOutputBaseDialogTest  (PASS)
atest MediaOutputDialogTest  (PASS)

Change-Id: Idd26d2b4e10dfcd00045184ddd2f9815a02ec7ce
This commit is contained in:
SongFerngWang
2022-04-18 17:43:22 +08:00
parent 04a6e834c6
commit 6197f495a9
7 changed files with 370 additions and 54 deletions

View File

@@ -2283,6 +2283,10 @@
<string name="media_output_broadcast_code">Password</string> <string name="media_output_broadcast_code">Password</string>
<!-- Button for change broadcast name and broadcast code [CHAR LIMIT=60] --> <!-- Button for change broadcast name and broadcast code [CHAR LIMIT=60] -->
<string name="media_output_broadcast_dialog_save">Save</string> <string name="media_output_broadcast_dialog_save">Save</string>
<!-- The "starting" text when Broadcast is starting [CHAR LIMIT=60] -->
<string name="media_output_broadcast_starting">Starting&#8230;</string>
<!-- The button text when Broadcast start failed [CHAR LIMIT=60] -->
<string name="media_output_broadcast_start_failed">Can\u2019t broadcast</string>
<!-- Label for clip data when copying the build number off QS [CHAR LIMIT=NONE]--> <!-- Label for clip data when copying the build number off QS [CHAR LIMIT=NONE]-->
<string name="build_number_clip_data_label">Build number</string> <string name="build_number_clip_data_label">Build number</string>

View File

@@ -19,7 +19,10 @@ package com.android.systemui.media.dialog;
import static android.view.WindowInsets.Type.navigationBars; import static android.view.WindowInsets.Type.navigationBars;
import static android.view.WindowInsets.Type.statusBars; import static android.view.WindowInsets.Type.statusBars;
import android.annotation.NonNull;
import android.app.WallpaperColors; import android.app.WallpaperColors;
import android.bluetooth.BluetoothLeBroadcast;
import android.bluetooth.BluetoothLeBroadcastMetadata;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.res.Configuration; import android.content.res.Configuration;
@@ -59,6 +62,9 @@ import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastSender; import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.systemui.statusbar.phone.SystemUIDialog;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
/** /**
* Base dialog for media output UI * Base dialog for media output UI
*/ */
@@ -69,6 +75,7 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
private static final String EMPTY_TITLE = " "; private static final String EMPTY_TITLE = " ";
private static final String PREF_NAME = "MediaOutputDialog"; private static final String PREF_NAME = "MediaOutputDialog";
private static final String PREF_IS_LE_BROADCAST_FIRST_LAUNCH = "PrefIsLeBroadcastFirstLaunch"; private static final String PREF_IS_LE_BROADCAST_FIRST_LAUNCH = "PrefIsLeBroadcastFirstLaunch";
private static final boolean DEBUG = true;
private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper()); private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
private final RecyclerView.LayoutManager mLayoutManager; private final RecyclerView.LayoutManager mLayoutManager;
@@ -91,6 +98,7 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
private Button mAppButton; private Button mAppButton;
private int mListMaxHeight; private int mListMaxHeight;
private WallpaperColors mWallpaperColors; private WallpaperColors mWallpaperColors;
private Executor mExecutor;
MediaOutputBaseAdapter mAdapter; MediaOutputBaseAdapter mAdapter;
@@ -103,6 +111,79 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
} }
}; };
private final BluetoothLeBroadcast.Callback mBroadcastCallback =
new BluetoothLeBroadcast.Callback() {
@Override
public void onBroadcastStarted(int reason, int broadcastId) {
if (DEBUG) {
Log.d(TAG, "onBroadcastStarted(), reason = " + reason
+ ", broadcastId = " + broadcastId);
}
mMainThreadHandler.post(() -> startLeBroadcastDialog());
}
@Override
public void onBroadcastStartFailed(int reason) {
if (DEBUG) {
Log.d(TAG, "onBroadcastStartFailed(), reason = " + reason);
}
handleLeBroadcastStartFailed();
}
@Override
public void onBroadcastMetadataChanged(int broadcastId,
@NonNull BluetoothLeBroadcastMetadata metadata) {
if (DEBUG) {
Log.d(TAG, "onBroadcastMetadataChanged(), broadcastId = " + broadcastId
+ ", metadata = " + metadata);
}
mMainThreadHandler.post(() -> refresh());
}
@Override
public void onBroadcastStopped(int reason, int broadcastId) {
if (DEBUG) {
Log.d(TAG, "onBroadcastStopped(), reason = " + reason
+ ", broadcastId = " + broadcastId);
}
mMainThreadHandler.post(() -> refresh());
}
@Override
public void onBroadcastStopFailed(int reason) {
if (DEBUG) {
Log.d(TAG, "onBroadcastStopFailed(), reason = " + reason);
}
mMainThreadHandler.post(() -> refresh());
}
@Override
public void onBroadcastUpdated(int reason, int broadcastId) {
if (DEBUG) {
Log.d(TAG, "onBroadcastUpdated(), reason = " + reason
+ ", broadcastId = " + broadcastId);
}
mMainThreadHandler.post(() -> refresh());
}
@Override
public void onBroadcastUpdateFailed(int reason, int broadcastId) {
if (DEBUG) {
Log.d(TAG, "onBroadcastUpdateFailed(), reason = " + reason
+ ", broadcastId = " + broadcastId);
}
mMainThreadHandler.post(() -> refresh());
}
@Override
public void onPlaybackStarted(int reason, int broadcastId) {
}
@Override
public void onPlaybackStopped(int reason, int broadcastId) {
}
};
public MediaOutputBaseDialog(Context context, BroadcastSender broadcastSender, public MediaOutputBaseDialog(Context context, BroadcastSender broadcastSender,
MediaOutputController mediaOutputController) { MediaOutputController mediaOutputController) {
super(context, R.style.Theme_SystemUI_Dialog_Media); super(context, R.style.Theme_SystemUI_Dialog_Media);
@@ -114,6 +195,7 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
mLayoutManager = new LinearLayoutManager(mContext); mLayoutManager = new LinearLayoutManager(mContext);
mListMaxHeight = context.getResources().getDimensionPixelSize( mListMaxHeight = context.getResources().getDimensionPixelSize(
R.dimen.media_output_dialog_list_max_height); R.dimen.media_output_dialog_list_max_height);
mExecutor = Executors.newSingleThreadExecutor();
} }
@Override @Override
@@ -171,11 +253,18 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
public void onStart() { public void onStart() {
super.onStart(); super.onStart();
mMediaOutputController.start(this); mMediaOutputController.start(this);
if(isBroadcastSupported()) {
mMediaOutputController.registerLeBroadcastServiceCallBack(mExecutor,
mBroadcastCallback);
}
} }
@Override @Override
public void onStop() { public void onStop() {
super.onStop(); super.onStop();
if(isBroadcastSupported()) {
mMediaOutputController.unregisterLeBroadcastServiceCallBack(mBroadcastCallback);
}
mMediaOutputController.stop(); mMediaOutputController.stop();
} }
@@ -254,35 +343,12 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
mAdapter.notifyDataSetChanged(); mAdapter.notifyDataSetChanged();
} }
} }
// Show when remote media session is available // Show when remote media session is available or
// when the device supports BT LE audio + media is playing
mStopButton.setVisibility(getStopButtonVisibility()); mStopButton.setVisibility(getStopButtonVisibility());
if (isBroadcastSupported() && mMediaOutputController.isPlaying()) { mStopButton.setEnabled(true);
mStopButton.setText(R.string.media_output_broadcast); mStopButton.setText(getStopButtonText());
mStopButton.setOnClickListener(v -> { mStopButton.setOnClickListener(v -> onStopButtonClick());
SharedPreferences sharedPref = mContext.getSharedPreferences(PREF_NAME,
Context.MODE_PRIVATE);
if (sharedPref != null
&& sharedPref.getBoolean(PREF_IS_LE_BROADCAST_FIRST_LAUNCH, true)) {
Log.d(TAG, "PREF_IS_LE_BROADCAST_FIRST_LAUNCH: true");
mMediaOutputController.launchLeBroadcastNotifyDialog(mDialogView,
mBroadcastSender,
MediaOutputController.BroadcastNotifyDialog.ACTION_FIRST_LAUNCH);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putBoolean(PREF_IS_LE_BROADCAST_FIRST_LAUNCH, false);
editor.apply();
} else {
mMediaOutputController.launchMediaOutputBroadcastDialog(mDialogView,
mBroadcastSender);
}
});
} else {
mStopButton.setOnClickListener(v -> {
mMediaOutputController.releaseSession();
dismiss();
});
}
} }
private Drawable resizeDrawable(Drawable drawable, int size) { private Drawable resizeDrawable(Drawable drawable, int size) {
@@ -301,6 +367,56 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
Bitmap.createScaledBitmap(bitmap, size, size, false)); Bitmap.createScaledBitmap(bitmap, size, size, false));
} }
protected void handleLeBroadcastStartFailed() {
mStopButton.setText(R.string.media_output_broadcast_start_failed);
mStopButton.setEnabled(false);
mMainThreadHandler.postDelayed(() -> refresh(), 3000);
}
protected void startLeBroadcast() {
mStopButton.setText(R.string.media_output_broadcast_starting);
mStopButton.setEnabled(false);
if (!mMediaOutputController.startBluetoothLeBroadcast()) {
// If the system can't execute "broadcast start", then UI shows the error.
handleLeBroadcastStartFailed();
}
}
protected boolean startLeBroadcastDialogForFirstTime(){
SharedPreferences sharedPref = mContext.getSharedPreferences(PREF_NAME,
Context.MODE_PRIVATE);
if (sharedPref != null
&& sharedPref.getBoolean(PREF_IS_LE_BROADCAST_FIRST_LAUNCH, true)) {
Log.d(TAG, "PREF_IS_LE_BROADCAST_FIRST_LAUNCH: true");
mMediaOutputController.launchLeBroadcastNotifyDialog(mDialogView,
mBroadcastSender,
MediaOutputController.BroadcastNotifyDialog.ACTION_FIRST_LAUNCH,
(d, w) -> {
startLeBroadcast();
});
SharedPreferences.Editor editor = sharedPref.edit();
editor.putBoolean(PREF_IS_LE_BROADCAST_FIRST_LAUNCH, false);
editor.apply();
return true;
}
return false;
}
protected void startLeBroadcastDialog() {
mMediaOutputController.launchMediaOutputBroadcastDialog(mDialogView,
mBroadcastSender);
refresh();
}
protected void stopLeBroadcast() {
mStopButton.setEnabled(false);
if (!mMediaOutputController.stopBluetoothLeBroadcast()) {
// If the system can't execute "broadcast stop", then UI does refresh.
mMainThreadHandler.post(() -> refresh());
}
}
abstract Drawable getAppSourceIcon(); abstract Drawable getAppSourceIcon();
abstract int getHeaderIconRes(); abstract int getHeaderIconRes();
@@ -315,6 +431,15 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
abstract int getStopButtonVisibility(); abstract int getStopButtonVisibility();
public CharSequence getStopButtonText() {
return mContext.getText(R.string.keyboard_key_media_stop);
}
public void onStopButtonClick() {
mMediaOutputController.releaseSession();
dismiss();
}
public boolean isBroadcastSupported() { public boolean isBroadcastSupported() {
return false; return false;
} }

View File

@@ -142,8 +142,11 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog {
mBroadcastNotify = getDialogView().requireViewById(R.id.broadcast_info); mBroadcastNotify = getDialogView().requireViewById(R.id.broadcast_info);
mBroadcastNotify.setOnClickListener(v -> { mBroadcastNotify.setOnClickListener(v -> {
mMediaOutputController.launchLeBroadcastNotifyDialog(null, null, mMediaOutputController.launchLeBroadcastNotifyDialog(
MediaOutputController.BroadcastNotifyDialog.ACTION_BROADCAST_INFO_ICON); /* view= */ null,
/* broadcastSender= */ null,
MediaOutputController.BroadcastNotifyDialog.ACTION_BROADCAST_INFO_ICON,
/* onClickListener= */ null);
}); });
mBroadcastName = getDialogView().requireViewById(R.id.broadcast_name_summary); mBroadcastName = getDialogView().requireViewById(R.id.broadcast_name_summary);
mBroadcastNameEdit = getDialogView().requireViewById(R.id.broadcast_name_edit); mBroadcastNameEdit = getDialogView().requireViewById(R.id.broadcast_name_edit);

View File

@@ -18,10 +18,13 @@ package com.android.systemui.media.dialog;
import static android.provider.Settings.ACTION_BLUETOOTH_PAIRING_SETTINGS; import static android.provider.Settings.ACTION_BLUETOOTH_PAIRING_SETTINGS;
import android.annotation.CallbackExecutor;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Notification; import android.app.Notification;
import android.app.WallpaperColors; import android.app.WallpaperColors;
import android.bluetooth.BluetoothLeBroadcast;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
@@ -58,7 +61,7 @@ import androidx.mediarouter.media.MediaRouterParams;
import com.android.settingslib.RestrictedLockUtilsInternal; import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.Utils; import com.android.settingslib.Utils;
import com.android.settingslib.bluetooth.BluetoothUtils; import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.media.BluetoothMediaDevice; import com.android.settingslib.media.BluetoothMediaDevice;
import com.android.settingslib.media.InfoMediaManager; import com.android.settingslib.media.InfoMediaManager;
@@ -83,6 +86,7 @@ import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
import javax.inject.Inject; import javax.inject.Inject;
@@ -642,17 +646,14 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
} }
void launchLeBroadcastNotifyDialog(View mediaOutputDialog, BroadcastSender broadcastSender, void launchLeBroadcastNotifyDialog(View mediaOutputDialog, BroadcastSender broadcastSender,
BroadcastNotifyDialog action) { BroadcastNotifyDialog action, final DialogInterface.OnClickListener listener) {
final AlertDialog.Builder builder = new AlertDialog.Builder(mContext); final AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
switch (action) { switch (action) {
case ACTION_FIRST_LAUNCH: case ACTION_FIRST_LAUNCH:
builder.setTitle(R.string.media_output_first_broadcast_title); builder.setTitle(R.string.media_output_first_broadcast_title);
builder.setMessage(R.string.media_output_first_notify_broadcast_message); builder.setMessage(R.string.media_output_first_notify_broadcast_message);
builder.setNegativeButton(android.R.string.cancel, null); builder.setNegativeButton(android.R.string.cancel, null);
builder.setPositiveButton(R.string.media_output_broadcast, builder.setPositiveButton(R.string.media_output_broadcast, listener);
(d, w) -> {
launchMediaOutputBroadcastDialog(mediaOutputDialog, broadcastSender);
});
break; break;
case ACTION_BROADCAST_INFO_ICON: case ACTION_BROADCAST_INFO_ICON:
builder.setTitle(R.string.media_output_broadcast); builder.setTitle(R.string.media_output_broadcast);
@@ -685,18 +686,64 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
|| features.contains(MediaRoute2Info.FEATURE_REMOTE_GROUP_PLAYBACK)); || features.contains(MediaRoute2Info.FEATURE_REMOTE_GROUP_PLAYBACK));
} }
boolean isBluetoothLeDevice(@NonNull MediaDevice device) { boolean isBroadcastSupported() {
if (device instanceof BluetoothMediaDevice) { LocalBluetoothLeBroadcast broadcast =
final CachedBluetoothDevice cachedDevice = mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile();
((BluetoothMediaDevice) device).getCachedDevice(); return broadcast != null ? true : false;
boolean isConnectedLeAudioDevice = }
(cachedDevice != null) ? cachedDevice.isConnectedLeAudioDevice() : false;
if (DEBUG) { boolean isBluetoothLeBroadcastEnabled() {
Log.d(TAG, "isConnectedLeAudioDevice=" + isConnectedLeAudioDevice); LocalBluetoothLeBroadcast broadcast =
} mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile();
return isConnectedLeAudioDevice; if (broadcast == null) {
return false;
} }
return false; return broadcast.isEnabled(null);
}
boolean startBluetoothLeBroadcast() {
LocalBluetoothLeBroadcast broadcast =
mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile();
if (broadcast == null) {
Log.d(TAG, "The broadcast profile is null");
return false;
}
broadcast.startBroadcast(getAppSourceName(), /*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;
}
void registerLeBroadcastServiceCallBack(
@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);
}
void unregisterLeBroadcastServiceCallBack(
@NonNull BluetoothLeBroadcast.Callback callback) {
LocalBluetoothLeBroadcast broadcast =
mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile();
if (broadcast == null) {
Log.d(TAG, "The broadcast profile is null");
return;
}
broadcast.unregisterServiceCallBack(callback);
} }
private boolean isPlayBackInfoLocal() { private boolean isPlayBackInfoLocal() {

View File

@@ -27,7 +27,6 @@ import androidx.core.graphics.drawable.IconCompat;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.UiEvent; import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.UiEventLogger;
import com.android.settingslib.media.MediaDevice;
import com.android.systemui.R; import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastSender; import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.SysUISingleton;
@@ -93,18 +92,41 @@ public class MediaOutputDialog extends MediaOutputBaseDialog {
isActiveRemoteDevice = mMediaOutputController.isActiveRemoteDevice( isActiveRemoteDevice = mMediaOutputController.isActiveRemoteDevice(
mMediaOutputController.getCurrentConnectedMediaDevice()); mMediaOutputController.getCurrentConnectedMediaDevice());
} }
boolean isBroadCastSupported = isBroadcastSupported(); boolean showBroadcastButton = isBroadcastSupported() && mMediaOutputController.isPlaying();
return (isActiveRemoteDevice || isBroadCastSupported) ? View.VISIBLE : View.GONE; return (isActiveRemoteDevice || showBroadcastButton) ? View.VISIBLE : View.GONE;
} }
@Override @Override
public boolean isBroadcastSupported() { public boolean isBroadcastSupported() {
MediaDevice device = mMediaOutputController.getCurrentConnectedMediaDevice(); return mMediaOutputController.isBroadcastSupported();
if (device == null) { }
return false;
@Override
public CharSequence getStopButtonText() {
int resId = R.string.keyboard_key_media_stop;
if (isBroadcastSupported() && mMediaOutputController.isPlaying()
&& !mMediaOutputController.isBluetoothLeBroadcastEnabled()) {
resId = R.string.media_output_broadcast;
}
return mContext.getText(resId);
}
@Override
public void onStopButtonClick() {
if (isBroadcastSupported() && mMediaOutputController.isPlaying()) {
if (!mMediaOutputController.isBluetoothLeBroadcastEnabled()) {
if (startLeBroadcastDialogForFirstTime()) {
return;
}
startLeBroadcast();
} else {
stopLeBroadcast();
}
} else {
mMediaOutputController.releaseSession();
dismiss();
} }
return mMediaOutputController.isBluetoothLeDevice(device);
} }
@VisibleForTesting @VisibleForTesting

View File

@@ -18,6 +18,7 @@ package com.android.systemui.media.dialog;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
@@ -26,18 +27,23 @@ import static org.mockito.Mockito.when;
import android.content.Context; import android.content.Context;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.media.session.MediaController;
import android.media.session.MediaSessionManager; import android.media.session.MediaSessionManager;
import android.media.session.PlaybackState;
import android.os.Bundle; import android.os.Bundle;
import android.testing.AndroidTestingRunner; import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper; import android.testing.TestableLooper;
import android.view.View; import android.view.View;
import android.widget.Button;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import androidx.core.graphics.drawable.IconCompat; import androidx.core.graphics.drawable.IconCompat;
import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import com.android.systemui.R; import com.android.systemui.R;
import com.android.systemui.SysuiTestCase; import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.DialogLaunchAnimator; import com.android.systemui.animation.DialogLaunchAnimator;
@@ -50,6 +56,8 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional; import java.util.Optional;
@SmallTest @SmallTest
@@ -61,8 +69,14 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase {
// Mock // Mock
private MediaOutputBaseAdapter mMediaOutputBaseAdapter = mock(MediaOutputBaseAdapter.class); private MediaOutputBaseAdapter mMediaOutputBaseAdapter = mock(MediaOutputBaseAdapter.class);
private MediaController mMediaController = mock(MediaController.class);
private PlaybackState mPlaybackState = mock(PlaybackState.class);
private MediaSessionManager mMediaSessionManager = mock(MediaSessionManager.class); private MediaSessionManager mMediaSessionManager = mock(MediaSessionManager.class);
private LocalBluetoothManager mLocalBluetoothManager = mock(LocalBluetoothManager.class); private LocalBluetoothManager mLocalBluetoothManager = mock(LocalBluetoothManager.class);
private final LocalBluetoothProfileManager mLocalBluetoothProfileManager = mock(
LocalBluetoothProfileManager.class);
private final LocalBluetoothLeBroadcast mLocalBluetoothLeBroadcast = mock(
LocalBluetoothLeBroadcast.class);
private ActivityStarter mStarter = mock(ActivityStarter.class); private ActivityStarter mStarter = mock(ActivityStarter.class);
private BroadcastSender mBroadcastSender = mock(BroadcastSender.class); private BroadcastSender mBroadcastSender = mock(BroadcastSender.class);
private NotificationEntryManager mNotificationEntryManager = private NotificationEntryManager mNotificationEntryManager =
@@ -71,15 +85,26 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase {
NearbyMediaDevicesManager.class); NearbyMediaDevicesManager.class);
private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class); private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
private List<MediaController> mMediaControllers = new ArrayList<>();
private MediaOutputBaseDialogImpl mMediaOutputBaseDialogImpl; private MediaOutputBaseDialogImpl mMediaOutputBaseDialogImpl;
private MediaOutputController mMediaOutputController; private MediaOutputController mMediaOutputController;
private int mHeaderIconRes; private int mHeaderIconRes;
private IconCompat mIconCompat; private IconCompat mIconCompat;
private CharSequence mHeaderTitle; private CharSequence mHeaderTitle;
private CharSequence mHeaderSubtitle; private CharSequence mHeaderSubtitle;
private String mStopText;
private boolean mIsBroadcasting;
@Before @Before
public void setUp() { public void setUp() {
when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBluetoothProfileManager);
when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(null);
when(mMediaController.getPlaybackState()).thenReturn(mPlaybackState);
when(mPlaybackState.getState()).thenReturn(PlaybackState.STATE_NONE);
when(mMediaController.getPackageName()).thenReturn(TEST_PACKAGE);
mMediaControllers.add(mMediaController);
when(mMediaSessionManager.getActiveSessions(any())).thenReturn(mMediaControllers);
mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE,
mMediaSessionManager, mLocalBluetoothManager, mStarter, mMediaSessionManager, mLocalBluetoothManager, mStarter,
mNotificationEntryManager, mDialogLaunchAnimator, mNotificationEntryManager, mDialogLaunchAnimator,
@@ -173,6 +198,59 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase {
verify(mMediaOutputBaseAdapter).notifyDataSetChanged(); verify(mMediaOutputBaseAdapter).notifyDataSetChanged();
} }
@Test
public void onStart_isBroadcasting_verifyRegisterLeBroadcastServiceCallBack() {
when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
mLocalBluetoothLeBroadcast);
mIsBroadcasting = true;
mMediaOutputBaseDialogImpl.onStart();
verify(mLocalBluetoothLeBroadcast).registerServiceCallBack(any(), any());
}
@Test
public void onStart_notBroadcasting_noRegisterLeBroadcastServiceCallBack() {
when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
mLocalBluetoothLeBroadcast);
mIsBroadcasting = false;
mMediaOutputBaseDialogImpl.onStart();
verify(mLocalBluetoothLeBroadcast, never()).registerServiceCallBack(any(), any());
}
@Test
public void onStart_isBroadcasting_verifyUnregisterLeBroadcastServiceCallBack() {
when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
mLocalBluetoothLeBroadcast);
mIsBroadcasting = true;
mMediaOutputBaseDialogImpl.onStop();
verify(mLocalBluetoothLeBroadcast).unregisterServiceCallBack(any());
}
@Test
public void onStop_notBroadcasting_noUnregisterLeBroadcastServiceCallBack() {
when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
mLocalBluetoothLeBroadcast);
mIsBroadcasting = false;
mMediaOutputBaseDialogImpl.onStop();
verify(mLocalBluetoothLeBroadcast, never()).unregisterServiceCallBack(any());
}
@Test
public void refresh_checkStopText() {
mStopText = "test_string";
mMediaOutputBaseDialogImpl.refresh();
final Button stop = mMediaOutputBaseDialogImpl.mDialogView.requireViewById(R.id.stop);
assertThat(stop.getText().toString()).isEqualTo(mStopText);
}
class MediaOutputBaseDialogImpl extends MediaOutputBaseDialog { class MediaOutputBaseDialogImpl extends MediaOutputBaseDialog {
MediaOutputBaseDialogImpl(Context context, BroadcastSender broadcastSender, MediaOutputBaseDialogImpl(Context context, BroadcastSender broadcastSender,
@@ -216,5 +294,15 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase {
int getStopButtonVisibility() { int getStopButtonVisibility() {
return 0; return 0;
} }
@Override
public boolean isBroadcastSupported() {
return mIsBroadcasting;
}
@Override
public CharSequence getStopButtonText() {
return mStopText;
}
} }
} }

View File

@@ -18,13 +18,16 @@ package com.android.systemui.media.dialog;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.media.MediaRoute2Info; import android.media.MediaRoute2Info;
import android.media.session.MediaController;
import android.media.session.MediaSessionManager; import android.media.session.MediaSessionManager;
import android.media.session.PlaybackState;
import android.testing.AndroidTestingRunner; import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper; import android.testing.TestableLooper;
import android.view.View; import android.view.View;
@@ -32,7 +35,9 @@ import android.view.View;
import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest;
import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.UiEventLogger;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import com.android.settingslib.media.LocalMediaManager; import com.android.settingslib.media.LocalMediaManager;
import com.android.settingslib.media.MediaDevice; import com.android.settingslib.media.MediaDevice;
import com.android.systemui.SysuiTestCase; import com.android.systemui.SysuiTestCase;
@@ -60,7 +65,13 @@ public class MediaOutputDialogTest extends SysuiTestCase {
// Mock // Mock
private final MediaSessionManager mMediaSessionManager = mock(MediaSessionManager.class); private final MediaSessionManager mMediaSessionManager = mock(MediaSessionManager.class);
private MediaController mMediaController = mock(MediaController.class);
private PlaybackState mPlaybackState = mock(PlaybackState.class);
private final LocalBluetoothManager mLocalBluetoothManager = mock(LocalBluetoothManager.class); private final LocalBluetoothManager mLocalBluetoothManager = mock(LocalBluetoothManager.class);
private final LocalBluetoothProfileManager mLocalBluetoothProfileManager = mock(
LocalBluetoothProfileManager.class);
private final LocalBluetoothLeBroadcast mLocalBluetoothLeBroadcast = mock(
LocalBluetoothLeBroadcast.class);
private final ActivityStarter mStarter = mock(ActivityStarter.class); private final ActivityStarter mStarter = mock(ActivityStarter.class);
private final BroadcastSender mBroadcastSender = mock(BroadcastSender.class); private final BroadcastSender mBroadcastSender = mock(BroadcastSender.class);
private final LocalMediaManager mLocalMediaManager = mock(LocalMediaManager.class); private final LocalMediaManager mLocalMediaManager = mock(LocalMediaManager.class);
@@ -72,12 +83,21 @@ public class MediaOutputDialogTest extends SysuiTestCase {
private final NearbyMediaDevicesManager mNearbyMediaDevicesManager = mock( private final NearbyMediaDevicesManager mNearbyMediaDevicesManager = mock(
NearbyMediaDevicesManager.class); NearbyMediaDevicesManager.class);
private List<MediaController> mMediaControllers = new ArrayList<>();
private MediaOutputDialog mMediaOutputDialog; private MediaOutputDialog mMediaOutputDialog;
private MediaOutputController mMediaOutputController; private MediaOutputController mMediaOutputController;
private final List<String> mFeatures = new ArrayList<>(); private final List<String> mFeatures = new ArrayList<>();
@Before @Before
public void setUp() { public void setUp() {
when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBluetoothProfileManager);
when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(null);
when(mMediaController.getPlaybackState()).thenReturn(mPlaybackState);
when(mPlaybackState.getState()).thenReturn(PlaybackState.STATE_NONE);
when(mMediaController.getPackageName()).thenReturn(TEST_PACKAGE);
mMediaControllers.add(mMediaController);
when(mMediaSessionManager.getActiveSessions(any())).thenReturn(mMediaControllers);
mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE,
mMediaSessionManager, mLocalBluetoothManager, mStarter, mMediaSessionManager, mLocalBluetoothManager, mStarter,
mNotificationEntryManager, mDialogLaunchAnimator, mNotificationEntryManager, mDialogLaunchAnimator,
@@ -116,6 +136,13 @@ public class MediaOutputDialogTest extends SysuiTestCase {
mFeatures.add(MediaRoute2Info.FEATURE_REMOTE_GROUP_PLAYBACK); mFeatures.add(MediaRoute2Info.FEATURE_REMOTE_GROUP_PLAYBACK);
assertThat(mMediaOutputDialog.getStopButtonVisibility()).isEqualTo(View.VISIBLE); assertThat(mMediaOutputDialog.getStopButtonVisibility()).isEqualTo(View.VISIBLE);
mFeatures.clear();
when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
mLocalBluetoothLeBroadcast);
when(mLocalBluetoothLeBroadcast.isEnabled(any())).thenReturn(false);
when(mPlaybackState.getState()).thenReturn(PlaybackState.STATE_PLAYING);
assertThat(mMediaOutputDialog.getStopButtonVisibility()).isEqualTo(View.VISIBLE);
} }
@Test @Test