Merge "Small clean up to get ready for receive state based triggering." into main
This commit is contained in:
@@ -34,7 +34,10 @@ import android.media.MediaMetadata;
|
||||
import android.media.session.MediaSession;
|
||||
import android.media.session.PlaybackState;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.IBinder;
|
||||
import android.os.Process;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
@@ -51,24 +54,21 @@ import com.android.settingslib.bluetooth.BluetoothUtils;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
import com.android.settingslib.bluetooth.VolumeControlProfile;
|
||||
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class AudioStreamMediaService extends Service {
|
||||
static final String BROADCAST_ID = "audio_stream_media_service_broadcast_id";
|
||||
static final String BROADCAST_TITLE = "audio_stream_media_service_broadcast_title";
|
||||
static final String DEVICES = "audio_stream_media_service_devices";
|
||||
private static final String TAG = "AudioStreamMediaService";
|
||||
private static final int NOTIFICATION_ID = 1;
|
||||
private static final int NOTIFICATION_ID = R.string.audio_streams_title;
|
||||
private static final int BROADCAST_LISTENING_NOW_TEXT = R.string.audio_streams_listening_now;
|
||||
private static final int BROADCAST_STREAM_PAUSED_TEXT = R.string.audio_streams_present_now;
|
||||
@VisibleForTesting static final String LEAVE_BROADCAST_ACTION = "leave_broadcast_action";
|
||||
@@ -113,17 +113,16 @@ public class AudioStreamMediaService extends Service {
|
||||
|
||||
private final MetricsFeatureProvider mMetricsFeatureProvider =
|
||||
FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
|
||||
private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
|
||||
private final AtomicBoolean mIsMuted = new AtomicBoolean(false);
|
||||
private final AtomicBoolean mIsHysteresis = new AtomicBoolean(false);
|
||||
private final HandlerThread mHandlerThread = new HandlerThread(TAG,
|
||||
Process.THREAD_PRIORITY_BACKGROUND);
|
||||
private boolean mIsMuted = false;
|
||||
// Set 25 as default as the volume range from `VolumeControlProfile` is from 0 to 255.
|
||||
// If the initial volume from `onDeviceVolumeChanged` is larger than zero (not muted), we will
|
||||
// override this value. Otherwise, we raise the volume to 25 when the play button is clicked.
|
||||
private final AtomicInteger mLatestPositiveVolume = new AtomicInteger(25);
|
||||
private final Object mLocalSessionLock = new Object();
|
||||
private int mLatestPositiveVolume = 25;
|
||||
private boolean mHysteresisModeFixAvailable;
|
||||
private int mBroadcastId;
|
||||
@Nullable private List<BluetoothDevice> mDevices;
|
||||
@Nullable private Map<BluetoothDevice, LocalBluetoothLeBroadcastSourceState> mStateByDevice;
|
||||
@Nullable private LocalBluetoothManager mLocalBtManager;
|
||||
@Nullable private AudioStreamsHelper mAudioStreamsHelper;
|
||||
@Nullable private LocalBluetoothLeBroadcastAssistant mLeBroadcastAssistant;
|
||||
@@ -154,7 +153,6 @@ public class AudioStreamMediaService extends Service {
|
||||
Log.w(TAG, "onCreate() : mLeBroadcastAssistant is null!");
|
||||
return;
|
||||
}
|
||||
mHysteresisModeFixAvailable = BluetoothUtils.isAudioSharingHysteresisModeFixAvailable(this);
|
||||
|
||||
mNotificationManager = getSystemService(NotificationManager.class);
|
||||
if (mNotificationManager == null) {
|
||||
@@ -162,7 +160,8 @@ public class AudioStreamMediaService extends Service {
|
||||
return;
|
||||
}
|
||||
|
||||
mExecutor.execute(
|
||||
mHandlerThread.start();
|
||||
getHandler().post(
|
||||
() -> {
|
||||
if (mLocalBtManager == null
|
||||
|| mLeBroadcastAssistant == null
|
||||
@@ -184,45 +183,49 @@ public class AudioStreamMediaService extends Service {
|
||||
mVolumeControl = mLocalBtManager.getProfileManager().getVolumeControlProfile();
|
||||
if (mVolumeControl != null) {
|
||||
mVolumeControlCallback = new VolumeControlCallback();
|
||||
mVolumeControl.registerCallback(mExecutor, mVolumeControlCallback);
|
||||
mVolumeControl.registerCallback(getHandler()::post, mVolumeControlCallback);
|
||||
}
|
||||
|
||||
mBroadcastAssistantCallback = new AssistantCallback();
|
||||
mLeBroadcastAssistant.registerServiceCallBack(
|
||||
mExecutor, mBroadcastAssistantCallback);
|
||||
getHandler()::post, mBroadcastAssistantCallback);
|
||||
|
||||
mHysteresisModeFixAvailable =
|
||||
BluetoothUtils.isAudioSharingHysteresisModeFixAvailable(this);
|
||||
});
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
Handler getHandler() {
|
||||
return mHandlerThread.getThreadHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
Log.d(TAG, "onDestroy()");
|
||||
super.onDestroy();
|
||||
if (BluetoothUtils.isAudioSharingUIAvailable(this)) {
|
||||
if (mDevices != null) {
|
||||
mDevices.clear();
|
||||
mDevices = null;
|
||||
}
|
||||
synchronized (mLocalSessionLock) {
|
||||
if (mLocalSession != null) {
|
||||
mLocalSession.release();
|
||||
mLocalSession = null;
|
||||
}
|
||||
}
|
||||
mExecutor.execute(
|
||||
() -> {
|
||||
if (mLocalBtManager != null) {
|
||||
mLocalBtManager.getEventManager().unregisterCallback(
|
||||
mBluetoothCallback);
|
||||
}
|
||||
if (mLeBroadcastAssistant != null && mBroadcastAssistantCallback != null) {
|
||||
mLeBroadcastAssistant.unregisterServiceCallBack(
|
||||
mBroadcastAssistantCallback);
|
||||
}
|
||||
if (mVolumeControl != null && mVolumeControlCallback != null) {
|
||||
mVolumeControl.unregisterCallback(mVolumeControlCallback);
|
||||
}
|
||||
});
|
||||
}
|
||||
getHandler().post(
|
||||
() -> {
|
||||
if (mStateByDevice != null) {
|
||||
mStateByDevice.clear();
|
||||
mStateByDevice = null;
|
||||
}
|
||||
if (mLocalSession != null) {
|
||||
mLocalSession.release();
|
||||
mLocalSession = null;
|
||||
}
|
||||
if (mLocalBtManager != null) {
|
||||
mLocalBtManager.getEventManager().unregisterCallback(
|
||||
mBluetoothCallback);
|
||||
}
|
||||
if (mLeBroadcastAssistant != null && mBroadcastAssistantCallback != null) {
|
||||
mLeBroadcastAssistant.unregisterServiceCallBack(
|
||||
mBroadcastAssistantCallback);
|
||||
}
|
||||
if (mVolumeControl != null && mVolumeControlCallback != null) {
|
||||
mVolumeControl.unregisterCallback(mVolumeControlCallback);
|
||||
}
|
||||
});
|
||||
mHandlerThread.quitSafely();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -233,53 +236,59 @@ public class AudioStreamMediaService extends Service {
|
||||
stopSelf();
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
mBroadcastId = intent.getIntExtra(BROADCAST_ID, -1);
|
||||
if (mBroadcastId == -1) {
|
||||
Log.w(TAG, "Invalid broadcast ID. Service will not start.");
|
||||
stopSelf();
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
var extra = intent.getParcelableArrayListExtra(DEVICES, BluetoothDevice.class);
|
||||
if (extra == null || extra.isEmpty()) {
|
||||
Log.w(TAG, "No device. Service will not start.");
|
||||
stopSelf();
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
mDevices = Collections.synchronizedList(extra);
|
||||
MediaSession.Token token =
|
||||
getOrCreateLocalMediaSession(intent.getStringExtra(BROADCAST_TITLE));
|
||||
startForeground(NOTIFICATION_ID, buildNotification(token));
|
||||
getHandler().post(() -> {
|
||||
mBroadcastId = intent.getIntExtra(BROADCAST_ID, -1);
|
||||
if (mBroadcastId == -1) {
|
||||
Log.w(TAG, "Invalid broadcast ID. Service will not start.");
|
||||
stopSelf();
|
||||
return;
|
||||
}
|
||||
var devices = intent.getParcelableArrayListExtra(DEVICES, BluetoothDevice.class);
|
||||
if (devices == null || devices.isEmpty()) {
|
||||
Log.w(TAG, "No device. Service will not start.");
|
||||
stopSelf();
|
||||
} else {
|
||||
mStateByDevice = new HashMap<>();
|
||||
devices.forEach(d -> mStateByDevice.put(d, STREAMING));
|
||||
MediaSession.Token token =
|
||||
getOrCreateLocalMediaSession(intent.getStringExtra(BROADCAST_TITLE));
|
||||
startForeground(NOTIFICATION_ID, buildNotification(token));
|
||||
}
|
||||
});
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
|
||||
private MediaSession.Token getOrCreateLocalMediaSession(String title) {
|
||||
synchronized (mLocalSessionLock) {
|
||||
if (mLocalSession != null) {
|
||||
return mLocalSession.getSessionToken();
|
||||
}
|
||||
mLocalSession = new MediaSession(this, TAG);
|
||||
mLocalSession.setMetadata(
|
||||
new MediaMetadata.Builder()
|
||||
.putString(MediaMetadata.METADATA_KEY_TITLE, title)
|
||||
.putLong(MediaMetadata.METADATA_KEY_DURATION, STATIC_PLAYBACK_DURATION)
|
||||
.build());
|
||||
mLocalSession.setActive(true);
|
||||
mLocalSession.setPlaybackState(getPlaybackState());
|
||||
mMediaSessionCallback = new MediaSessionCallback();
|
||||
mLocalSession.setCallback(mMediaSessionCallback);
|
||||
if (mLocalSession != null) {
|
||||
return mLocalSession.getSessionToken();
|
||||
}
|
||||
mLocalSession = new MediaSession(this, TAG);
|
||||
mLocalSession.setMetadata(
|
||||
new MediaMetadata.Builder()
|
||||
.putString(MediaMetadata.METADATA_KEY_TITLE, title)
|
||||
.putLong(MediaMetadata.METADATA_KEY_DURATION, STATIC_PLAYBACK_DURATION)
|
||||
.build());
|
||||
mLocalSession.setActive(true);
|
||||
mLocalSession.setPlaybackState(getPlaybackState());
|
||||
mMediaSessionCallback = new MediaSessionCallback();
|
||||
mLocalSession.setCallback(mMediaSessionCallback, getHandler());
|
||||
return mLocalSession.getSessionToken();
|
||||
}
|
||||
|
||||
private PlaybackState getPlaybackState() {
|
||||
if (mIsHysteresis.get()) {
|
||||
if (isAllDeviceHysteresis()) {
|
||||
return mPlayStateHysteresisBuilder.build();
|
||||
}
|
||||
return mIsMuted.get() ? mPlayStatePausingBuilder.build() : mPlayStatePlayingBuilder.build();
|
||||
return mIsMuted ? mPlayStatePausingBuilder.build() : mPlayStatePlayingBuilder.build();
|
||||
}
|
||||
|
||||
private boolean isAllDeviceHysteresis() {
|
||||
return mHysteresisModeFixAvailable && mStateByDevice != null
|
||||
&& mStateByDevice.values().stream().allMatch(v -> v == PAUSED);
|
||||
}
|
||||
|
||||
private String getDeviceName() {
|
||||
if (mDevices == null || mDevices.isEmpty() || mLocalBtManager == null) {
|
||||
if (mStateByDevice == null || mStateByDevice.isEmpty() || mLocalBtManager == null) {
|
||||
return DEFAULT_DEVICE_NAME;
|
||||
}
|
||||
|
||||
@@ -288,7 +297,8 @@ public class AudioStreamMediaService extends Service {
|
||||
return DEFAULT_DEVICE_NAME;
|
||||
}
|
||||
|
||||
CachedBluetoothDevice device = manager.findDevice(mDevices.get(0));
|
||||
CachedBluetoothDevice device = manager.findDevice(
|
||||
mStateByDevice.keySet().iterator().next());
|
||||
return device != null ? device.getName() : DEFAULT_DEVICE_NAME;
|
||||
}
|
||||
|
||||
@@ -304,7 +314,7 @@ public class AudioStreamMediaService extends Service {
|
||||
.setSmallIcon(com.android.settingslib.R.drawable.ic_bt_le_audio_sharing)
|
||||
.setStyle(mediaStyle)
|
||||
.setContentText(getString(
|
||||
mIsHysteresis.get() ? BROADCAST_STREAM_PAUSED_TEXT :
|
||||
isAllDeviceHysteresis() ? BROADCAST_STREAM_PAUSED_TEXT :
|
||||
BROADCAST_LISTENING_NOW_TEXT))
|
||||
.setSilent(true);
|
||||
return notificationBuilder.build();
|
||||
@@ -333,7 +343,8 @@ public class AudioStreamMediaService extends Service {
|
||||
public void onReceiveStateChanged(
|
||||
BluetoothDevice sink, int sourceId, BluetoothLeBroadcastReceiveState state) {
|
||||
super.onReceiveStateChanged(sink, sourceId, state);
|
||||
if (!mHysteresisModeFixAvailable || mDevices == null || !mDevices.contains(sink)) {
|
||||
if (!mHysteresisModeFixAvailable || mStateByDevice == null
|
||||
|| !mStateByDevice.containsKey(sink)) {
|
||||
return;
|
||||
}
|
||||
var sourceState = LocalBluetoothLeBroadcastAssistant.getLocalSourceState(state);
|
||||
@@ -343,12 +354,10 @@ public class AudioStreamMediaService extends Service {
|
||||
if (!streaming && !paused) {
|
||||
return;
|
||||
}
|
||||
// Atomically update mIsHysteresis if its current value is not the current paused state
|
||||
if (mIsHysteresis.compareAndSet(!paused, paused)) {
|
||||
synchronized (mLocalSessionLock) {
|
||||
if (mLocalSession == null) {
|
||||
return;
|
||||
}
|
||||
boolean shouldUpdate = mStateByDevice.get(sink) != sourceState;
|
||||
if (shouldUpdate) {
|
||||
mStateByDevice.put(sink, sourceState);
|
||||
if (mLocalSession != null) {
|
||||
mLocalSession.setPlaybackState(getPlaybackState());
|
||||
if (mNotificationManager != null) {
|
||||
mNotificationManager.notify(
|
||||
@@ -356,7 +365,7 @@ public class AudioStreamMediaService extends Service {
|
||||
buildNotification(mLocalSession.getSessionToken())
|
||||
);
|
||||
}
|
||||
Log.d(TAG, "updating hysteresis mode to : " + paused);
|
||||
Log.d(TAG, "updating source state to : " + sourceState);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -374,24 +383,22 @@ public class AudioStreamMediaService extends Service {
|
||||
@Override
|
||||
public void onDeviceVolumeChanged(
|
||||
@NonNull BluetoothDevice device, @IntRange(from = -255, to = 255) int volume) {
|
||||
if (mDevices == null || mDevices.isEmpty()) {
|
||||
if (mStateByDevice == null || mStateByDevice.isEmpty()) {
|
||||
Log.w(TAG, "active device or device has source is null!");
|
||||
return;
|
||||
}
|
||||
Log.d(
|
||||
TAG,
|
||||
"onDeviceVolumeChanged() bluetoothDevice : " + device + " volume: " + volume);
|
||||
if (mDevices.contains(device)) {
|
||||
if (mStateByDevice.containsKey(device)) {
|
||||
if (volume == 0) {
|
||||
mIsMuted.set(true);
|
||||
mIsMuted = true;
|
||||
} else {
|
||||
mIsMuted.set(false);
|
||||
mLatestPositiveVolume.set(volume);
|
||||
mIsMuted = false;
|
||||
mLatestPositiveVolume = volume;
|
||||
}
|
||||
synchronized (mLocalSessionLock) {
|
||||
if (mLocalSession != null) {
|
||||
mLocalSession.setPlaybackState(getPlaybackState());
|
||||
}
|
||||
if (mLocalSession != null) {
|
||||
mLocalSession.setPlaybackState(getPlaybackState());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -400,10 +407,12 @@ public class AudioStreamMediaService extends Service {
|
||||
private class BtCallback implements BluetoothCallback {
|
||||
@Override
|
||||
public void onBluetoothStateChanged(int bluetoothState) {
|
||||
if (BluetoothAdapter.STATE_OFF == bluetoothState) {
|
||||
Log.d(TAG, "onBluetoothStateChanged() : stopSelf");
|
||||
stopSelf();
|
||||
}
|
||||
getHandler().post(() -> {
|
||||
if (BluetoothAdapter.STATE_OFF == bluetoothState) {
|
||||
Log.d(TAG, "onBluetoothStateChanged() : stopSelf");
|
||||
stopSelf();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -411,24 +420,17 @@ public class AudioStreamMediaService extends Service {
|
||||
@NonNull CachedBluetoothDevice cachedDevice,
|
||||
@ConnectionState int state,
|
||||
int bluetoothProfile) {
|
||||
if (state == BluetoothAdapter.STATE_DISCONNECTED
|
||||
&& bluetoothProfile == BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT
|
||||
&& mDevices != null) {
|
||||
mDevices.remove(cachedDevice.getDevice());
|
||||
cachedDevice
|
||||
.getMemberDevice()
|
||||
.forEach(
|
||||
m -> {
|
||||
// Check nullability to pass NullAway check
|
||||
if (mDevices != null) {
|
||||
mDevices.remove(m.getDevice());
|
||||
}
|
||||
});
|
||||
}
|
||||
if (mDevices == null || mDevices.isEmpty()) {
|
||||
Log.d(TAG, "onProfileConnectionStateChanged() : stopSelf");
|
||||
stopSelf();
|
||||
}
|
||||
getHandler().post(() -> {
|
||||
if (state == BluetoothAdapter.STATE_DISCONNECTED
|
||||
&& bluetoothProfile == BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT
|
||||
&& mStateByDevice != null) {
|
||||
mStateByDevice.remove(cachedDevice.getDevice());
|
||||
}
|
||||
if (mStateByDevice == null || mStateByDevice.isEmpty()) {
|
||||
Log.d(TAG, "onProfileConnectionStateChanged() : stopSelf");
|
||||
stopSelf();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -454,10 +456,8 @@ public class AudioStreamMediaService extends Service {
|
||||
@Override
|
||||
public void onSeekTo(long pos) {
|
||||
Log.d(TAG, "onSeekTo: " + pos);
|
||||
synchronized (mLocalSessionLock) {
|
||||
if (mLocalSession != null) {
|
||||
mLocalSession.setPlaybackState(getPlaybackState());
|
||||
}
|
||||
if (mLocalSession != null) {
|
||||
mLocalSession.setPlaybackState(getPlaybackState());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -484,28 +484,26 @@ public class AudioStreamMediaService extends Service {
|
||||
}
|
||||
|
||||
private void handleOnPlay() {
|
||||
if (mDevices == null || mDevices.isEmpty()) {
|
||||
if (mStateByDevice == null || mStateByDevice.isEmpty()) {
|
||||
Log.w(TAG, "active device or device has source is null!");
|
||||
return;
|
||||
}
|
||||
Log.d(
|
||||
TAG,
|
||||
"onPlay() setting volume for device : "
|
||||
+ mDevices.getFirst()
|
||||
+ " volume: "
|
||||
+ mLatestPositiveVolume.get());
|
||||
setDeviceVolume(mDevices.getFirst(), mLatestPositiveVolume.get());
|
||||
mStateByDevice.keySet().forEach(device -> {
|
||||
Log.d(TAG, "onPlay() setting volume for device : " + device + " volume: "
|
||||
+ mLatestPositiveVolume);
|
||||
setDeviceVolume(device, mLatestPositiveVolume);
|
||||
});
|
||||
}
|
||||
|
||||
private void handleOnPause() {
|
||||
if (mDevices == null || mDevices.isEmpty()) {
|
||||
if (mStateByDevice == null || mStateByDevice.isEmpty()) {
|
||||
Log.w(TAG, "active device or device has source is null!");
|
||||
return;
|
||||
}
|
||||
Log.d(
|
||||
TAG,
|
||||
"onPause() setting volume for device : " + mDevices.getFirst() + " volume: " + 0);
|
||||
setDeviceVolume(mDevices.getFirst(), /* volume= */ 0);
|
||||
mStateByDevice.keySet().forEach(device -> {
|
||||
Log.d(TAG, "onPause() setting volume for device : " + device + " volume: " + 0);
|
||||
setDeviceVolume(device, /* volume= */ 0);
|
||||
});
|
||||
}
|
||||
|
||||
private void setDeviceVolume(BluetoothDevice device, int volume) {
|
||||
@@ -514,7 +512,7 @@ public class AudioStreamMediaService extends Service {
|
||||
ThreadUtils.postOnBackgroundThread(
|
||||
() -> {
|
||||
if (mVolumeControl != null) {
|
||||
mVolumeControl.setDeviceVolume(device, volume, true);
|
||||
mVolumeControl.setDeviceVolume(device, volume, false);
|
||||
mMetricsFeatureProvider.action(
|
||||
getApplicationContext(), event, volume == 0 ? 1 : 0);
|
||||
}
|
||||
|
@@ -28,7 +28,6 @@ import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
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;
|
||||
@@ -52,7 +51,9 @@ import android.media.session.ISession;
|
||||
import android.media.session.ISessionController;
|
||||
import android.media.session.MediaSessionManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.RemoteException;
|
||||
import android.platform.test.flag.junit.SetFlagsRule;
|
||||
import android.util.DisplayMetrics;
|
||||
@@ -81,14 +82,12 @@ import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.android.util.concurrent.InlineExecutorService;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.shadow.api.Shadow;
|
||||
import org.robolectric.util.ReflectionHelpers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(
|
||||
@@ -122,6 +121,7 @@ public class AudioStreamMediaServiceTest {
|
||||
@Mock private PackageManager mPackageManager;
|
||||
@Mock private DisplayMetrics mDisplayMetrics;
|
||||
@Mock private Context mContext;
|
||||
@Mock private Handler mHandler;
|
||||
private FakeFeatureFactory mFeatureFactory;
|
||||
private AudioStreamMediaService mAudioStreamMediaService;
|
||||
|
||||
@@ -145,11 +145,18 @@ public class AudioStreamMediaServiceTest {
|
||||
when(mCachedBluetoothDevice.getName()).thenReturn(DEVICE_NAME);
|
||||
when(mLocalBluetoothProfileManager.getVolumeControlProfile())
|
||||
.thenReturn(mVolumeControlProfile);
|
||||
|
||||
mAudioStreamMediaService = spy(new AudioStreamMediaService());
|
||||
when(mHandler.post(any(Runnable.class))).thenAnswer(invocation -> {
|
||||
((Runnable) invocation.getArgument(0)).run();
|
||||
return null;
|
||||
});
|
||||
when(mHandler.getLooper()).thenReturn(Looper.getMainLooper());
|
||||
mAudioStreamMediaService = spy(new AudioStreamMediaService() {
|
||||
@Override
|
||||
Handler getHandler() {
|
||||
return mHandler;
|
||||
}
|
||||
});
|
||||
ReflectionHelpers.setField(mAudioStreamMediaService, "mBase", mContext);
|
||||
ReflectionHelpers.setField(
|
||||
mAudioStreamMediaService, "mExecutor", new InlineExecutorService());
|
||||
when(mAudioStreamMediaService.getSystemService(anyString()))
|
||||
.thenReturn(mMediaSessionManager);
|
||||
when(mMediaSessionManager.createSession(any(), anyString(), any())).thenReturn(mISession);
|
||||
@@ -391,31 +398,6 @@ public class AudioStreamMediaServiceTest {
|
||||
verify(mAudioStreamMediaService).stopSelf();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bluetoothCallback_onMemberDeviceDisconnect_stopSelf() {
|
||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||
when(mCachedBluetoothDevice.getDevice()).thenReturn(mock(BluetoothDevice.class));
|
||||
CachedBluetoothDevice member = mock(CachedBluetoothDevice.class);
|
||||
when(mCachedBluetoothDevice.getMemberDevice()).thenReturn(Set.of(member));
|
||||
when(member.getDevice()).thenReturn(mDevice);
|
||||
var devices = new ArrayList<BluetoothDevice>();
|
||||
devices.add(mDevice);
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(BROADCAST_ID, 1);
|
||||
intent.putParcelableArrayListExtra(DEVICES, devices);
|
||||
|
||||
mAudioStreamMediaService.onCreate();
|
||||
assertThat(mAudioStreamMediaService.mBluetoothCallback).isNotNull();
|
||||
mAudioStreamMediaService.onStartCommand(intent, /* flags= */ 0, /* startId= */ 0);
|
||||
mAudioStreamMediaService.mBluetoothCallback.onProfileConnectionStateChanged(
|
||||
mCachedBluetoothDevice,
|
||||
BluetoothAdapter.STATE_DISCONNECTED,
|
||||
BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
|
||||
|
||||
verify(mAudioStreamMediaService).stopSelf();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mediaSessionCallback_onPause_setVolume() {
|
||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||
|
Reference in New Issue
Block a user