Use LocalBluetoothLeBroadcastSourceState
.
Test: atest Bug: 308368124 Flag: com.android.settingslib.flags.enable_le_audio_sharing Change-Id: Ic49a6782b63c91e95dd16898b5443585068e45f0
This commit is contained in:
@@ -82,7 +82,7 @@ public class BluetoothDetailsAudioSharingController extends BluetoothDetailsCont
|
|||||||
mProfilesContainer.removeAll();
|
mProfilesContainer.removeAll();
|
||||||
mProfilesContainer.addPreference(createAudioSharingPreference());
|
mProfilesContainer.addPreference(createAudioSharingPreference());
|
||||||
if ((BluetoothUtils.isActiveLeAudioDevice(mCachedDevice)
|
if ((BluetoothUtils.isActiveLeAudioDevice(mCachedDevice)
|
||||||
|| AudioStreamsHelper.hasConnectedBroadcastSource(
|
|| AudioStreamsHelper.hasBroadcastSource(
|
||||||
mCachedDevice, mLocalBluetoothManager))
|
mCachedDevice, mLocalBluetoothManager))
|
||||||
&& !BluetoothUtils.isBroadcasting(mLocalBluetoothManager)) {
|
&& !BluetoothUtils.isBroadcasting(mLocalBluetoothManager)) {
|
||||||
mProfilesContainer.addPreference(createFindAudioStreamPreference());
|
mProfilesContainer.addPreference(createFindAudioStreamPreference());
|
||||||
|
@@ -16,6 +16,10 @@
|
|||||||
|
|
||||||
package com.android.settings.connecteddevice.audiosharing.audiostreams;
|
package com.android.settings.connecteddevice.audiosharing.audiostreams;
|
||||||
|
|
||||||
|
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState.PAUSED;
|
||||||
|
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState.STREAMING;
|
||||||
|
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.getLocalSourceState;
|
||||||
|
|
||||||
import android.app.settings.SettingsEnums;
|
import android.app.settings.SettingsEnums;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.bluetooth.BluetoothLeBroadcastAssistant;
|
import android.bluetooth.BluetoothLeBroadcastAssistant;
|
||||||
@@ -42,7 +46,6 @@ import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
|||||||
import com.android.settingslib.utils.ThreadUtils;
|
import com.android.settingslib.utils.ThreadUtils;
|
||||||
import com.android.settingslib.widget.ActionButtonsPreference;
|
import com.android.settingslib.widget.ActionButtonsPreference;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
@@ -75,20 +78,19 @@ public class AudioStreamButtonController extends BasePreferenceController
|
|||||||
int sourceId,
|
int sourceId,
|
||||||
BluetoothLeBroadcastReceiveState state) {
|
BluetoothLeBroadcastReceiveState state) {
|
||||||
super.onReceiveStateChanged(sink, sourceId, state);
|
super.onReceiveStateChanged(sink, sourceId, state);
|
||||||
boolean shouldUpdateButton =
|
var localSourceState = getLocalSourceState(state);
|
||||||
BluetoothUtils.isAudioSharingHysteresisModeFixAvailable(mContext)
|
boolean shouldUpdateButton = mHysteresisModeFixAvailable
|
||||||
? AudioStreamsHelper.hasSourcePresent(state)
|
? (localSourceState == PAUSED || localSourceState == STREAMING)
|
||||||
: AudioStreamsHelper.isConnected(state);
|
: localSourceState == STREAMING;
|
||||||
if (shouldUpdateButton) {
|
if (shouldUpdateButton) {
|
||||||
updateButton();
|
updateButton();
|
||||||
if (AudioStreamsHelper.isConnected(state)) {
|
// TODO(b/308368124): Verify if this log is too noisy.
|
||||||
mMetricsFeatureProvider.action(
|
mMetricsFeatureProvider.action(
|
||||||
mContext,
|
mContext,
|
||||||
SettingsEnums.ACTION_AUDIO_STREAM_JOIN_SUCCEED,
|
SettingsEnums.ACTION_AUDIO_STREAM_JOIN_SUCCEED,
|
||||||
SOURCE_ORIGIN_REPOSITORY);
|
SOURCE_ORIGIN_REPOSITORY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSourceAddFailed(
|
public void onSourceAddFailed(
|
||||||
@@ -113,6 +115,7 @@ public class AudioStreamButtonController extends BasePreferenceController
|
|||||||
private final AudioStreamsHelper mAudioStreamsHelper;
|
private final AudioStreamsHelper mAudioStreamsHelper;
|
||||||
private final @Nullable LocalBluetoothLeBroadcastAssistant mLeBroadcastAssistant;
|
private final @Nullable LocalBluetoothLeBroadcastAssistant mLeBroadcastAssistant;
|
||||||
private final MetricsFeatureProvider mMetricsFeatureProvider;
|
private final MetricsFeatureProvider mMetricsFeatureProvider;
|
||||||
|
private final boolean mHysteresisModeFixAvailable;
|
||||||
private @Nullable ActionButtonsPreference mPreference;
|
private @Nullable ActionButtonsPreference mPreference;
|
||||||
private int mBroadcastId = -1;
|
private int mBroadcastId = -1;
|
||||||
|
|
||||||
@@ -121,6 +124,8 @@ public class AudioStreamButtonController extends BasePreferenceController
|
|||||||
mExecutor = Executors.newSingleThreadExecutor();
|
mExecutor = Executors.newSingleThreadExecutor();
|
||||||
mAudioStreamsHelper = new AudioStreamsHelper(Utils.getLocalBtManager(context));
|
mAudioStreamsHelper = new AudioStreamsHelper(Utils.getLocalBtManager(context));
|
||||||
mLeBroadcastAssistant = mAudioStreamsHelper.getLeBroadcastAssistant();
|
mLeBroadcastAssistant = mAudioStreamsHelper.getLeBroadcastAssistant();
|
||||||
|
mHysteresisModeFixAvailable = BluetoothUtils.isAudioSharingHysteresisModeFixAvailable(
|
||||||
|
context);
|
||||||
mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
|
mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,14 +160,8 @@ public class AudioStreamButtonController extends BasePreferenceController
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<BluetoothLeBroadcastReceiveState> sources =
|
boolean isConnected = mAudioStreamsHelper.getConnectedBroadcastIdAndState(
|
||||||
BluetoothUtils.isAudioSharingHysteresisModeFixAvailable(mContext)
|
mHysteresisModeFixAvailable).containsKey(mBroadcastId);
|
||||||
? mAudioStreamsHelper.getAllPresentSources()
|
|
||||||
: mAudioStreamsHelper.getAllConnectedSources();
|
|
||||||
boolean isConnected =
|
|
||||||
sources.stream()
|
|
||||||
.map(BluetoothLeBroadcastReceiveState::getBroadcastId)
|
|
||||||
.anyMatch(connectedBroadcastId -> connectedBroadcastId == mBroadcastId);
|
|
||||||
|
|
||||||
View.OnClickListener onClickListener;
|
View.OnClickListener onClickListener;
|
||||||
|
|
||||||
|
@@ -16,9 +16,10 @@
|
|||||||
|
|
||||||
package com.android.settings.connecteddevice.audiosharing.audiostreams;
|
package com.android.settings.connecteddevice.audiosharing.audiostreams;
|
||||||
|
|
||||||
import static com.android.settingslib.flags.Flags.audioSharingHysteresisModeFix;
|
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState;
|
||||||
|
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState.PAUSED;
|
||||||
import static java.util.stream.Collectors.toList;
|
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState.STREAMING;
|
||||||
|
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.getLocalSourceState;
|
||||||
|
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.bluetooth.BluetoothLeBroadcastAssistant;
|
import android.bluetooth.BluetoothLeBroadcastAssistant;
|
||||||
@@ -61,6 +62,7 @@ public class AudioStreamHeaderController extends BasePreferenceController
|
|||||||
private final Executor mExecutor;
|
private final Executor mExecutor;
|
||||||
private final AudioStreamsHelper mAudioStreamsHelper;
|
private final AudioStreamsHelper mAudioStreamsHelper;
|
||||||
@Nullable private final LocalBluetoothLeBroadcastAssistant mLeBroadcastAssistant;
|
@Nullable private final LocalBluetoothLeBroadcastAssistant mLeBroadcastAssistant;
|
||||||
|
private final boolean mHysteresisModeFixAvailable;
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
final BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback =
|
final BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback =
|
||||||
@@ -83,13 +85,13 @@ public class AudioStreamHeaderController extends BasePreferenceController
|
|||||||
int sourceId,
|
int sourceId,
|
||||||
BluetoothLeBroadcastReceiveState state) {
|
BluetoothLeBroadcastReceiveState state) {
|
||||||
super.onReceiveStateChanged(sink, sourceId, state);
|
super.onReceiveStateChanged(sink, sourceId, state);
|
||||||
if (AudioStreamsHelper.isConnected(state)) {
|
var localSourceState = getLocalSourceState(state);
|
||||||
|
if (localSourceState == STREAMING) {
|
||||||
updateSummary();
|
updateSummary();
|
||||||
mAudioStreamsHelper.startMediaService(
|
mAudioStreamsHelper.startMediaService(
|
||||||
mContext, mBroadcastId, mBroadcastName);
|
mContext, mBroadcastId, mBroadcastName);
|
||||||
} else if (BluetoothUtils.isAudioSharingHysteresisModeFixAvailable(mContext)
|
} else if (mHysteresisModeFixAvailable && localSourceState == PAUSED) {
|
||||||
&& AudioStreamsHelper.hasSourcePresent(state)) {
|
// if source paused, only update the summary
|
||||||
// if source present but not connected, only update the summary
|
|
||||||
updateSummary();
|
updateSummary();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -105,6 +107,8 @@ public class AudioStreamHeaderController extends BasePreferenceController
|
|||||||
mExecutor = Executors.newSingleThreadExecutor();
|
mExecutor = Executors.newSingleThreadExecutor();
|
||||||
mAudioStreamsHelper = new AudioStreamsHelper(Utils.getLocalBtManager(context));
|
mAudioStreamsHelper = new AudioStreamsHelper(Utils.getLocalBtManager(context));
|
||||||
mLeBroadcastAssistant = mAudioStreamsHelper.getLeBroadcastAssistant();
|
mLeBroadcastAssistant = mAudioStreamsHelper.getLeBroadcastAssistant();
|
||||||
|
mHysteresisModeFixAvailable = BluetoothUtils.isAudioSharingHysteresisModeFixAvailable(
|
||||||
|
context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -151,38 +155,9 @@ public class AudioStreamHeaderController extends BasePreferenceController
|
|||||||
var unused =
|
var unused =
|
||||||
ThreadUtils.postOnBackgroundThread(
|
ThreadUtils.postOnBackgroundThread(
|
||||||
() -> {
|
() -> {
|
||||||
var connectedSourceList =
|
var sourceState = mAudioStreamsHelper.getConnectedBroadcastIdAndState(
|
||||||
mAudioStreamsHelper.getAllPresentSources().stream()
|
mHysteresisModeFixAvailable).get(mBroadcastId);
|
||||||
.filter(
|
var latestSummary = getLatestSummary(sourceState);
|
||||||
state ->
|
|
||||||
(state.getBroadcastId()
|
|
||||||
== mBroadcastId))
|
|
||||||
.collect(toList());
|
|
||||||
|
|
||||||
var latestSummary =
|
|
||||||
audioSharingHysteresisModeFix()
|
|
||||||
? connectedSourceList.isEmpty()
|
|
||||||
? AUDIO_STREAM_HEADER_NOT_LISTENING_SUMMARY
|
|
||||||
: (connectedSourceList.stream()
|
|
||||||
.anyMatch(
|
|
||||||
AudioStreamsHelper
|
|
||||||
::isConnected)
|
|
||||||
? mContext.getString(
|
|
||||||
AUDIO_STREAM_HEADER_LISTENING_NOW_SUMMARY)
|
|
||||||
: mContext.getString(
|
|
||||||
AUDIO_STREAM_HEADER_PRESENT_NOW_SUMMARY))
|
|
||||||
: mAudioStreamsHelper.getAllConnectedSources().stream()
|
|
||||||
.map(
|
|
||||||
BluetoothLeBroadcastReceiveState
|
|
||||||
::getBroadcastId)
|
|
||||||
.anyMatch(
|
|
||||||
connectedBroadcastId ->
|
|
||||||
connectedBroadcastId
|
|
||||||
== mBroadcastId)
|
|
||||||
? mContext.getString(
|
|
||||||
AUDIO_STREAM_HEADER_LISTENING_NOW_SUMMARY)
|
|
||||||
: AUDIO_STREAM_HEADER_NOT_LISTENING_SUMMARY;
|
|
||||||
|
|
||||||
ThreadUtils.postOnMainThread(
|
ThreadUtils.postOnMainThread(
|
||||||
() -> {
|
() -> {
|
||||||
if (mHeaderController != null) {
|
if (mHeaderController != null) {
|
||||||
@@ -212,4 +187,16 @@ public class AudioStreamHeaderController extends BasePreferenceController
|
|||||||
mBroadcastName = broadcastName;
|
mBroadcastName = broadcastName;
|
||||||
mBroadcastId = broadcastId;
|
mBroadcastId = broadcastId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getLatestSummary(@Nullable LocalBluetoothLeBroadcastSourceState state) {
|
||||||
|
if (state == null) {
|
||||||
|
return AUDIO_STREAM_HEADER_NOT_LISTENING_SUMMARY;
|
||||||
|
}
|
||||||
|
if (mHysteresisModeFixAvailable) {
|
||||||
|
return state == STREAMING
|
||||||
|
? mContext.getString(AUDIO_STREAM_HEADER_LISTENING_NOW_SUMMARY)
|
||||||
|
: mContext.getString(AUDIO_STREAM_HEADER_PRESENT_NOW_SUMMARY);
|
||||||
|
}
|
||||||
|
return mContext.getString(AUDIO_STREAM_HEADER_LISTENING_NOW_SUMMARY);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -16,8 +16,6 @@
|
|||||||
|
|
||||||
package com.android.settings.connecteddevice.audiosharing.audiostreams;
|
package com.android.settings.connecteddevice.audiosharing.audiostreams;
|
||||||
|
|
||||||
import static java.util.Collections.emptyList;
|
|
||||||
|
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.NotificationChannel;
|
import android.app.NotificationChannel;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
@@ -25,7 +23,6 @@ import android.app.Service;
|
|||||||
import android.app.settings.SettingsEnums;
|
import android.app.settings.SettingsEnums;
|
||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.bluetooth.BluetoothLeBroadcastReceiveState;
|
|
||||||
import android.bluetooth.BluetoothProfile;
|
import android.bluetooth.BluetoothProfile;
|
||||||
import android.bluetooth.BluetoothVolumeControl;
|
import android.bluetooth.BluetoothVolumeControl;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@@ -107,6 +104,7 @@ public class AudioStreamMediaService extends Service {
|
|||||||
// override this value. Otherwise, we raise the volume to 25 when the play button is clicked.
|
// 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 AtomicInteger mLatestPositiveVolume = new AtomicInteger(25);
|
||||||
private final Object mLocalSessionLock = new Object();
|
private final Object mLocalSessionLock = new Object();
|
||||||
|
private boolean mHysteresisModeFixAvailable;
|
||||||
private int mBroadcastId;
|
private int mBroadcastId;
|
||||||
@Nullable private List<BluetoothDevice> mDevices;
|
@Nullable private List<BluetoothDevice> mDevices;
|
||||||
@Nullable private LocalBluetoothManager mLocalBtManager;
|
@Nullable private LocalBluetoothManager mLocalBtManager;
|
||||||
@@ -139,6 +137,7 @@ public class AudioStreamMediaService extends Service {
|
|||||||
Log.w(TAG, "onCreate() : mLeBroadcastAssistant is null!");
|
Log.w(TAG, "onCreate() : mLeBroadcastAssistant is null!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
mHysteresisModeFixAvailable = BluetoothUtils.isAudioSharingHysteresisModeFixAvailable(this);
|
||||||
|
|
||||||
mNotificationManager = getSystemService(NotificationManager.class);
|
mNotificationManager = getSystemService(NotificationManager.class);
|
||||||
if (mNotificationManager == null) {
|
if (mNotificationManager == null) {
|
||||||
@@ -309,13 +308,9 @@ public class AudioStreamMediaService extends Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void handleRemoveSource() {
|
private void handleRemoveSource() {
|
||||||
List<BluetoothLeBroadcastReceiveState> connected =
|
if (mAudioStreamsHelper != null
|
||||||
mAudioStreamsHelper == null
|
&& !mAudioStreamsHelper.getConnectedBroadcastIdAndState(
|
||||||
? emptyList()
|
mHysteresisModeFixAvailable).containsKey(mBroadcastId)) {
|
||||||
: mAudioStreamsHelper.getAllConnectedSources();
|
|
||||||
if (connected.stream()
|
|
||||||
.map(BluetoothLeBroadcastReceiveState::getBroadcastId)
|
|
||||||
.noneMatch(id -> id == mBroadcastId)) {
|
|
||||||
stopSelf();
|
stopSelf();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -19,6 +19,12 @@ package com.android.settings.connecteddevice.audiosharing.audiostreams;
|
|||||||
import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamMediaService.BROADCAST_ID;
|
import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamMediaService.BROADCAST_ID;
|
||||||
import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamMediaService.BROADCAST_TITLE;
|
import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamMediaService.BROADCAST_TITLE;
|
||||||
import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamMediaService.DEVICES;
|
import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamMediaService.DEVICES;
|
||||||
|
import static com.android.settingslib.bluetooth.BluetoothUtils.isAudioSharingHysteresisModeFixAvailable;
|
||||||
|
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState;
|
||||||
|
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState.DECRYPTION_FAILED;
|
||||||
|
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState.PAUSED;
|
||||||
|
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState.STREAMING;
|
||||||
|
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.getLocalSourceState;
|
||||||
|
|
||||||
import static java.util.Collections.emptyList;
|
import static java.util.Collections.emptyList;
|
||||||
import static java.util.Collections.emptyMap;
|
import static java.util.Collections.emptyMap;
|
||||||
@@ -32,6 +38,7 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
import androidx.fragment.app.FragmentActivity;
|
import androidx.fragment.app.FragmentActivity;
|
||||||
@@ -67,12 +74,6 @@ public class AudioStreamsHelper {
|
|||||||
|
|
||||||
private final @Nullable LocalBluetoothManager mBluetoothManager;
|
private final @Nullable LocalBluetoothManager mBluetoothManager;
|
||||||
private final @Nullable LocalBluetoothLeBroadcastAssistant mLeBroadcastAssistant;
|
private final @Nullable LocalBluetoothLeBroadcastAssistant mLeBroadcastAssistant;
|
||||||
// Referring to Broadcast Audio Scan Service 1.0
|
|
||||||
// Table 3.9: Broadcast Receive State characteristic format
|
|
||||||
// 0x00000000: 0b0 = Not synchronized to BIS_index[x]
|
|
||||||
// 0xFFFFFFFF: Failed to sync to BIG
|
|
||||||
private static final long BIS_SYNC_NOT_SYNC_TO_BIS = 0x00000000L;
|
|
||||||
private static final long BIS_SYNC_FAILED_SYNC_TO_BIG = 0xFFFFFFFFL;
|
|
||||||
|
|
||||||
AudioStreamsHelper(@Nullable LocalBluetoothManager bluetoothManager) {
|
AudioStreamsHelper(@Nullable LocalBluetoothManager bluetoothManager) {
|
||||||
mBluetoothManager = bluetoothManager;
|
mBluetoothManager = bluetoothManager;
|
||||||
@@ -141,16 +142,31 @@ public class AudioStreamsHelper {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Retrieves a list of all LE broadcast receive states from active sinks. */
|
/**
|
||||||
public List<BluetoothLeBroadcastReceiveState> getAllConnectedSources() {
|
* Gets a map of connected broadcast IDs to their corresponding local broadcast source states.
|
||||||
if (mLeBroadcastAssistant == null) {
|
*
|
||||||
Log.w(TAG, "getAllSources(): LeBroadcastAssistant is null!");
|
* <p>If multiple sources have the same broadcast ID, the state of the source that is
|
||||||
return emptyList();
|
* {@code STREAMING} is preferred.
|
||||||
|
*/
|
||||||
|
public Map<Integer, LocalBluetoothLeBroadcastSourceState> getConnectedBroadcastIdAndState(
|
||||||
|
boolean hysteresisModeFixAvailable) {
|
||||||
|
if (mBluetoothManager == null || mLeBroadcastAssistant == null) {
|
||||||
|
Log.w(TAG,
|
||||||
|
"getConnectedBroadcastIdAndState(): BluetoothManager or LeBroadcastAssistant "
|
||||||
|
+ "is null!");
|
||||||
|
return emptyMap();
|
||||||
}
|
}
|
||||||
return getConnectedBluetoothDevices(mBluetoothManager, /* inSharingOnly= */ true).stream()
|
return getConnectedBluetoothDevices(mBluetoothManager, /* inSharingOnly= */ true).stream()
|
||||||
.flatMap(sink -> mLeBroadcastAssistant.getAllSources(sink).stream())
|
.flatMap(sink -> mLeBroadcastAssistant.getAllSources(sink).stream())
|
||||||
.filter(AudioStreamsHelper::isConnected)
|
.map(state -> new Pair<>(state.getBroadcastId(), getLocalSourceState(state)))
|
||||||
.toList();
|
.filter(pair -> pair.second == STREAMING
|
||||||
|
|| (hysteresisModeFixAvailable && pair.second == PAUSED))
|
||||||
|
.collect(toMap(
|
||||||
|
p -> p.first,
|
||||||
|
p -> p.second,
|
||||||
|
(existingState, newState) -> existingState == STREAMING ? existingState
|
||||||
|
: newState
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Retrieves a list of all LE broadcast receive states keyed by each active device. */
|
/** Retrieves a list of all LE broadcast receive states keyed by each active device. */
|
||||||
@@ -163,47 +179,12 @@ public class AudioStreamsHelper {
|
|||||||
.collect(toMap(Function.identity(), mLeBroadcastAssistant::getAllSources));
|
.collect(toMap(Function.identity(), mLeBroadcastAssistant::getAllSources));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Retrieves a list of all LE broadcast receive states from sinks with source present. */
|
|
||||||
@VisibleForTesting
|
|
||||||
public List<BluetoothLeBroadcastReceiveState> getAllPresentSources() {
|
|
||||||
if (mLeBroadcastAssistant == null) {
|
|
||||||
Log.w(TAG, "getAllPresentSources(): LeBroadcastAssistant is null!");
|
|
||||||
return emptyList();
|
|
||||||
}
|
|
||||||
return getConnectedBluetoothDevices(mBluetoothManager, /* inSharingOnly= */ true).stream()
|
|
||||||
.flatMap(sink -> mLeBroadcastAssistant.getAllSources(sink).stream())
|
|
||||||
.filter(AudioStreamsHelper::hasSourcePresent)
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Retrieves LocalBluetoothLeBroadcastAssistant. */
|
/** Retrieves LocalBluetoothLeBroadcastAssistant. */
|
||||||
@Nullable
|
@Nullable
|
||||||
public LocalBluetoothLeBroadcastAssistant getLeBroadcastAssistant() {
|
public LocalBluetoothLeBroadcastAssistant getLeBroadcastAssistant() {
|
||||||
return mLeBroadcastAssistant;
|
return mLeBroadcastAssistant;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Checks the connectivity status based on the provided broadcast receive state. */
|
|
||||||
public static boolean isConnected(BluetoothLeBroadcastReceiveState state) {
|
|
||||||
return state.getBisSyncState().stream()
|
|
||||||
.anyMatch(
|
|
||||||
bitmap ->
|
|
||||||
(bitmap != BIS_SYNC_NOT_SYNC_TO_BIS
|
|
||||||
&& bitmap != BIS_SYNC_FAILED_SYNC_TO_BIG));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Checks the connectivity status based on the provided broadcast receive state. */
|
|
||||||
public static boolean hasSourcePresent(BluetoothLeBroadcastReceiveState state) {
|
|
||||||
// Referring to Broadcast Audio Scan Service 1.0
|
|
||||||
// All zero address means no source on the sink device
|
|
||||||
return !state.getSourceDevice().getAddress().equals("00:00:00:00:00:00");
|
|
||||||
}
|
|
||||||
|
|
||||||
static boolean isBadCode(BluetoothLeBroadcastReceiveState state) {
|
|
||||||
return state.getPaSyncState() == BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_SYNCHRONIZED
|
|
||||||
&& state.getBigEncryptionState()
|
|
||||||
== BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_BAD_CODE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a {@code CachedBluetoothDevice} that is either connected to a broadcast source or is
|
* Returns a {@code CachedBluetoothDevice} that is either connected to a broadcast source or is
|
||||||
* a connected LE device.
|
* a connected LE device.
|
||||||
@@ -226,7 +207,7 @@ public class AudioStreamsHelper {
|
|||||||
}
|
}
|
||||||
var deviceHasSource =
|
var deviceHasSource =
|
||||||
leadDevices.stream()
|
leadDevices.stream()
|
||||||
.filter(device -> hasConnectedBroadcastSource(device, manager))
|
.filter(device -> hasBroadcastSource(device, manager))
|
||||||
.findFirst();
|
.findFirst();
|
||||||
if (deviceHasSource.isPresent()) {
|
if (deviceHasSource.isPresent()) {
|
||||||
Log.d(
|
Log.d(
|
||||||
@@ -258,38 +239,38 @@ public class AudioStreamsHelper {
|
|||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
return leadDevices.stream()
|
return leadDevices.stream()
|
||||||
.filter(device -> hasConnectedBroadcastSource(device, manager))
|
.filter(device -> hasBroadcastSource(device, manager))
|
||||||
.findFirst();
|
.findFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if {@link CachedBluetoothDevice} has connected to a broadcast source.
|
* Check if {@link CachedBluetoothDevice} has a broadcast source that is in STREAMING, PAUSED
|
||||||
|
* or DECRYPTION_FAILED state.
|
||||||
*
|
*
|
||||||
* @param cachedDevice The cached bluetooth device to check.
|
* @param cachedDevice The cached bluetooth device to check.
|
||||||
* @param localBtManager The BT manager to provide BT functions.
|
* @param localBtManager The BT manager to provide BT functions.
|
||||||
* @return Whether the device has connected to a broadcast source.
|
* @return Whether the device has a broadcast source.
|
||||||
*/
|
*/
|
||||||
public static boolean hasConnectedBroadcastSource(
|
public static boolean hasBroadcastSource(
|
||||||
CachedBluetoothDevice cachedDevice, LocalBluetoothManager localBtManager) {
|
CachedBluetoothDevice cachedDevice, LocalBluetoothManager localBtManager) {
|
||||||
if (localBtManager == null) {
|
if (localBtManager == null) {
|
||||||
Log.d(TAG, "Skip check hasConnectedBroadcastSource due to bt manager is null");
|
Log.d(TAG, "Skip check hasBroadcastSource due to bt manager is null");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
LocalBluetoothLeBroadcastAssistant assistant =
|
LocalBluetoothLeBroadcastAssistant assistant =
|
||||||
localBtManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
|
localBtManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
|
||||||
if (assistant == null) {
|
if (assistant == null) {
|
||||||
Log.d(TAG, "Skip check hasConnectedBroadcastSource due to assistant profile is null");
|
Log.d(TAG, "Skip check hasBroadcastSource due to assistant profile is null");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
List<BluetoothLeBroadcastReceiveState> sourceList =
|
List<BluetoothLeBroadcastReceiveState> sourceList =
|
||||||
assistant.getAllSources(cachedDevice.getDevice());
|
assistant.getAllSources(cachedDevice.getDevice());
|
||||||
if (!sourceList.isEmpty()
|
boolean hysteresisModeFixAvailable = isAudioSharingHysteresisModeFixAvailable(
|
||||||
&& (BluetoothUtils.isAudioSharingHysteresisModeFixAvailable(
|
localBtManager.getContext());
|
||||||
localBtManager.getContext())
|
if (hasReceiveState(sourceList, hysteresisModeFixAvailable)) {
|
||||||
|| sourceList.stream().anyMatch(AudioStreamsHelper::isConnected))) {
|
|
||||||
Log.d(
|
Log.d(
|
||||||
TAG,
|
TAG,
|
||||||
"Lead device has connected broadcast source, device = "
|
"Lead device has broadcast source, device = "
|
||||||
+ cachedDevice.getDevice().getAnonymizedAddress());
|
+ cachedDevice.getDevice().getAnonymizedAddress());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -297,13 +278,10 @@ public class AudioStreamsHelper {
|
|||||||
for (CachedBluetoothDevice device : cachedDevice.getMemberDevice()) {
|
for (CachedBluetoothDevice device : cachedDevice.getMemberDevice()) {
|
||||||
List<BluetoothLeBroadcastReceiveState> list =
|
List<BluetoothLeBroadcastReceiveState> list =
|
||||||
assistant.getAllSources(device.getDevice());
|
assistant.getAllSources(device.getDevice());
|
||||||
if (!list.isEmpty()
|
if (hasReceiveState(list, hysteresisModeFixAvailable)) {
|
||||||
&& (BluetoothUtils.isAudioSharingHysteresisModeFixAvailable(
|
|
||||||
localBtManager.getContext())
|
|
||||||
|| list.stream().anyMatch(AudioStreamsHelper::isConnected))) {
|
|
||||||
Log.d(
|
Log.d(
|
||||||
TAG,
|
TAG,
|
||||||
"Member device has connected broadcast source, device = "
|
"Member device has broadcast source, device = "
|
||||||
+ device.getDevice().getAnonymizedAddress());
|
+ device.getDevice().getAnonymizedAddress());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -311,6 +289,18 @@ public class AudioStreamsHelper {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean hasReceiveState(List<BluetoothLeBroadcastReceiveState> states,
|
||||||
|
boolean hysteresisModeFixAvailable) {
|
||||||
|
return states.stream().anyMatch(state -> {
|
||||||
|
var localSourceState = getLocalSourceState(state);
|
||||||
|
if (hysteresisModeFixAvailable) {
|
||||||
|
return localSourceState == STREAMING || localSourceState == DECRYPTION_FAILED
|
||||||
|
|| localSourceState == PAUSED;
|
||||||
|
}
|
||||||
|
return localSourceState == STREAMING || localSourceState == DECRYPTION_FAILED;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a list of connected Bluetooth devices that belongs to one {@link
|
* Retrieves a list of connected Bluetooth devices that belongs to one {@link
|
||||||
* CachedBluetoothDevice} that's either connected to a broadcast source or is a connected LE
|
* CachedBluetoothDevice} that's either connected to a broadcast source or is a connected LE
|
||||||
|
@@ -16,23 +16,17 @@
|
|||||||
|
|
||||||
package com.android.settings.connecteddevice.audiosharing.audiostreams;
|
package com.android.settings.connecteddevice.audiosharing.audiostreams;
|
||||||
|
|
||||||
|
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.getLocalSourceState;
|
||||||
|
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.bluetooth.BluetoothLeBroadcastMetadata;
|
import android.bluetooth.BluetoothLeBroadcastMetadata;
|
||||||
import android.bluetooth.BluetoothLeBroadcastReceiveState;
|
import android.bluetooth.BluetoothLeBroadcastReceiveState;
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
import com.android.settingslib.bluetooth.BluetoothUtils;
|
|
||||||
|
|
||||||
public class AudioStreamsProgressCategoryCallback extends AudioStreamsBroadcastAssistantCallback {
|
public class AudioStreamsProgressCategoryCallback extends AudioStreamsBroadcastAssistantCallback {
|
||||||
private static final String TAG = "AudioStreamsProgressCategoryCallback";
|
|
||||||
|
|
||||||
private final Context mContext;
|
|
||||||
private final AudioStreamsProgressCategoryController mCategoryController;
|
private final AudioStreamsProgressCategoryController mCategoryController;
|
||||||
|
|
||||||
public AudioStreamsProgressCategoryCallback(
|
public AudioStreamsProgressCategoryCallback(
|
||||||
Context context,
|
|
||||||
AudioStreamsProgressCategoryController audioStreamsProgressCategoryController) {
|
AudioStreamsProgressCategoryController audioStreamsProgressCategoryController) {
|
||||||
mContext = context;
|
|
||||||
mCategoryController = audioStreamsProgressCategoryController;
|
mCategoryController = audioStreamsProgressCategoryController;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,15 +34,11 @@ public class AudioStreamsProgressCategoryCallback extends AudioStreamsBroadcastA
|
|||||||
public void onReceiveStateChanged(
|
public void onReceiveStateChanged(
|
||||||
BluetoothDevice sink, int sourceId, BluetoothLeBroadcastReceiveState state) {
|
BluetoothDevice sink, int sourceId, BluetoothLeBroadcastReceiveState state) {
|
||||||
super.onReceiveStateChanged(sink, sourceId, state);
|
super.onReceiveStateChanged(sink, sourceId, state);
|
||||||
|
var sourceState = getLocalSourceState(state);
|
||||||
if (AudioStreamsHelper.isConnected(state)) {
|
switch (sourceState) {
|
||||||
mCategoryController.handleSourceConnected(sink, state);
|
case STREAMING -> mCategoryController.handleSourceStreaming(sink, state);
|
||||||
} else if (AudioStreamsHelper.isBadCode(state)) {
|
case DECRYPTION_FAILED -> mCategoryController.handleSourceConnectBadCode(state);
|
||||||
mCategoryController.handleSourceConnectBadCode(state);
|
case PAUSED -> mCategoryController.handleSourcePaused(sink, state);
|
||||||
} else if (BluetoothUtils.isAudioSharingHysteresisModeFixAvailable(mContext)
|
|
||||||
&& AudioStreamsHelper.hasSourcePresent(state)) {
|
|
||||||
// Keep this check as the last, source might also present in above states
|
|
||||||
mCategoryController.handleSourcePresent(sink, state);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -16,6 +16,12 @@
|
|||||||
|
|
||||||
package com.android.settings.connecteddevice.audiosharing.audiostreams;
|
package com.android.settings.connecteddevice.audiosharing.audiostreams;
|
||||||
|
|
||||||
|
import static com.android.settingslib.bluetooth.BluetoothUtils.isAudioSharingHysteresisModeFixAvailable;
|
||||||
|
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState.DECRYPTION_FAILED;
|
||||||
|
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState.PAUSED;
|
||||||
|
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState.STREAMING;
|
||||||
|
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.getLocalSourceState;
|
||||||
|
|
||||||
import static java.util.Collections.emptyList;
|
import static java.util.Collections.emptyList;
|
||||||
import static java.util.stream.Collectors.toMap;
|
import static java.util.stream.Collectors.toMap;
|
||||||
|
|
||||||
@@ -137,6 +143,7 @@ public class AudioStreamsProgressCategoryController extends BasePreferenceContro
|
|||||||
private final @Nullable LocalBluetoothManager mBluetoothManager;
|
private final @Nullable LocalBluetoothManager mBluetoothManager;
|
||||||
private final ConcurrentHashMap<Integer, AudioStreamPreference> mBroadcastIdToPreferenceMap =
|
private final ConcurrentHashMap<Integer, AudioStreamPreference> mBroadcastIdToPreferenceMap =
|
||||||
new ConcurrentHashMap<>();
|
new ConcurrentHashMap<>();
|
||||||
|
private final boolean mHysteresisModeFixAvailable;
|
||||||
private @Nullable BluetoothLeBroadcastMetadata mSourceFromQrCode;
|
private @Nullable BluetoothLeBroadcastMetadata mSourceFromQrCode;
|
||||||
private SourceOriginForLogging mSourceFromQrCodeOriginForLogging;
|
private SourceOriginForLogging mSourceFromQrCodeOriginForLogging;
|
||||||
@Nullable private AudioStreamsProgressCategoryPreference mCategoryPreference;
|
@Nullable private AudioStreamsProgressCategoryPreference mCategoryPreference;
|
||||||
@@ -149,7 +156,9 @@ public class AudioStreamsProgressCategoryController extends BasePreferenceContro
|
|||||||
mAudioStreamsHelper = new AudioStreamsHelper(mBluetoothManager);
|
mAudioStreamsHelper = new AudioStreamsHelper(mBluetoothManager);
|
||||||
mMediaControlHelper = new MediaControlHelper(mContext, mBluetoothManager);
|
mMediaControlHelper = new MediaControlHelper(mContext, mBluetoothManager);
|
||||||
mLeBroadcastAssistant = mAudioStreamsHelper.getLeBroadcastAssistant();
|
mLeBroadcastAssistant = mAudioStreamsHelper.getLeBroadcastAssistant();
|
||||||
mBroadcastAssistantCallback = new AudioStreamsProgressCategoryCallback(context, this);
|
mBroadcastAssistantCallback = new AudioStreamsProgressCategoryCallback(this);
|
||||||
|
mHysteresisModeFixAvailable = BluetoothUtils.isAudioSharingHysteresisModeFixAvailable(
|
||||||
|
mContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -260,7 +269,7 @@ public class AudioStreamsProgressCategoryController extends BasePreferenceContro
|
|||||||
// change it's state.
|
// change it's state.
|
||||||
existingPreference.setAudioStreamMetadata(source);
|
existingPreference.setAudioStreamMetadata(source);
|
||||||
if (fromState != AudioStreamState.SOURCE_ADDED
|
if (fromState != AudioStreamState.SOURCE_ADDED
|
||||||
&& (!isAudioSharingHysteresisModeFixAvailable(mContext)
|
&& (!mHysteresisModeFixAvailable
|
||||||
|| fromState != AudioStreamState.SOURCE_PRESENT)) {
|
|| fromState != AudioStreamState.SOURCE_PRESENT)) {
|
||||||
Log.w(
|
Log.w(
|
||||||
TAG,
|
TAG,
|
||||||
@@ -336,8 +345,8 @@ public class AudioStreamsProgressCategoryController extends BasePreferenceContro
|
|||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "handleSourceLost()");
|
Log.d(TAG, "handleSourceLost()");
|
||||||
}
|
}
|
||||||
if (mAudioStreamsHelper.getAllConnectedSources().stream()
|
if (mAudioStreamsHelper.getConnectedBroadcastIdAndState(
|
||||||
.anyMatch(connected -> connected.getBroadcastId() == broadcastId)) {
|
mHysteresisModeFixAvailable).containsKey(broadcastId)) {
|
||||||
Log.d(
|
Log.d(
|
||||||
TAG,
|
TAG,
|
||||||
"handleSourceLost() : keep this preference as the source is still connected.");
|
"handleSourceLost() : keep this preference as the source is still connected.");
|
||||||
@@ -366,14 +375,12 @@ public class AudioStreamsProgressCategoryController extends BasePreferenceContro
|
|||||||
// not, means the source is removed from the sink, we move back the preference to SYNCED
|
// not, means the source is removed from the sink, we move back the preference to SYNCED
|
||||||
// state.
|
// state.
|
||||||
if ((preference.getAudioStreamState() == AudioStreamState.SOURCE_ADDED
|
if ((preference.getAudioStreamState() == AudioStreamState.SOURCE_ADDED
|
||||||
|| (isAudioSharingHysteresisModeFixAvailable(mContext)
|
|| (mHysteresisModeFixAvailable
|
||||||
&& preference.getAudioStreamState()
|
&& preference.getAudioStreamState()
|
||||||
== AudioStreamState.SOURCE_PRESENT))
|
== AudioStreamState.SOURCE_PRESENT))
|
||||||
&& mAudioStreamsHelper.getAllConnectedSources().stream()
|
&& !mAudioStreamsHelper.getConnectedBroadcastIdAndState(
|
||||||
.noneMatch(
|
mHysteresisModeFixAvailable).containsKey(
|
||||||
connected ->
|
preference.getAudioStreamBroadcastId())) {
|
||||||
connected.getBroadcastId()
|
|
||||||
== preference.getAudioStreamBroadcastId())) {
|
|
||||||
|
|
||||||
ThreadUtils.postOnMainThread(
|
ThreadUtils.postOnMainThread(
|
||||||
() -> {
|
() -> {
|
||||||
@@ -395,27 +402,27 @@ public class AudioStreamsProgressCategoryController extends BasePreferenceContro
|
|||||||
// Expect one of the following:
|
// Expect one of the following:
|
||||||
// 1) No preference existed, create new preference with state SOURCE_ADDED
|
// 1) No preference existed, create new preference with state SOURCE_ADDED
|
||||||
// 2) Any other state, move to SOURCE_ADDED
|
// 2) Any other state, move to SOURCE_ADDED
|
||||||
void handleSourceConnected(
|
void handleSourceStreaming(
|
||||||
BluetoothDevice device, BluetoothLeBroadcastReceiveState receiveState) {
|
BluetoothDevice device, BluetoothLeBroadcastReceiveState receiveState) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "handleSourceConnected()");
|
Log.d(TAG, "handleSourceStreaming()");
|
||||||
}
|
}
|
||||||
if (!AudioStreamsHelper.isConnected(receiveState)) {
|
if (getLocalSourceState(receiveState) != STREAMING) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var broadcastIdConnected = receiveState.getBroadcastId();
|
var broadcastIdStreaming = receiveState.getBroadcastId();
|
||||||
Optional<BluetoothLeBroadcastMetadata> metadata =
|
Optional<BluetoothLeBroadcastMetadata> metadata =
|
||||||
getMetadataMatchingByBroadcastId(
|
getMetadataMatchingByBroadcastId(
|
||||||
device, receiveState.getSourceId(), broadcastIdConnected);
|
device, receiveState.getSourceId(), broadcastIdStreaming);
|
||||||
handleQrCodeWithUnsetBroadcastIdIfNeeded(metadata, receiveState);
|
handleQrCodeWithUnsetBroadcastIdIfNeeded(metadata, receiveState);
|
||||||
mBroadcastIdToPreferenceMap.compute(
|
mBroadcastIdToPreferenceMap.compute(
|
||||||
broadcastIdConnected,
|
broadcastIdStreaming,
|
||||||
(k, existingPreference) -> {
|
(k, existingPreference) -> {
|
||||||
if (existingPreference == null) {
|
if (existingPreference == null) {
|
||||||
// No existing preference for this source even if it's already connected,
|
// No existing preference for this source even if it's already streaming,
|
||||||
// add one and set initial state to SOURCE_ADDED. This could happen because
|
// add one and set initial state to SOURCE_ADDED. This could happen because
|
||||||
// we retrieves the connected source during onStart() from
|
// we retrieves the streaming source during onStart() from
|
||||||
// AudioStreamsHelper#getAllConnectedSources() even before the source is
|
// AudioStreamsHelper#getAllStreamingSources() even before the source is
|
||||||
// founded by scanning.
|
// founded by scanning.
|
||||||
return metadata.isPresent()
|
return metadata.isPresent()
|
||||||
? addNewPreference(
|
? addNewPreference(
|
||||||
@@ -440,7 +447,7 @@ public class AudioStreamsProgressCategoryController extends BasePreferenceContro
|
|||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "handleSourceConnectBadCode()");
|
Log.d(TAG, "handleSourceConnectBadCode()");
|
||||||
}
|
}
|
||||||
if (!AudioStreamsHelper.isBadCode(receiveState)) {
|
if (getLocalSourceState(receiveState) != DECRYPTION_FAILED) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mBroadcastIdToPreferenceMap.computeIfPresent(
|
mBroadcastIdToPreferenceMap.computeIfPresent(
|
||||||
@@ -467,29 +474,28 @@ public class AudioStreamsProgressCategoryController extends BasePreferenceContro
|
|||||||
|
|
||||||
// Find preference by receiveState and decide next state.
|
// Find preference by receiveState and decide next state.
|
||||||
// Expect one preference existed, move to SOURCE_PRESENT
|
// Expect one preference existed, move to SOURCE_PRESENT
|
||||||
void handleSourcePresent(
|
void handleSourcePaused(
|
||||||
BluetoothDevice device, BluetoothLeBroadcastReceiveState receiveState) {
|
BluetoothDevice device, BluetoothLeBroadcastReceiveState receiveState) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "handleSourcePresent()");
|
Log.d(TAG, "handleSourcePaused()");
|
||||||
}
|
}
|
||||||
if (!AudioStreamsHelper.hasSourcePresent(receiveState)) {
|
if (!mHysteresisModeFixAvailable || getLocalSourceState(receiveState) != PAUSED) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var broadcastIdConnected = receiveState.getBroadcastId();
|
var broadcastIdPaused = receiveState.getBroadcastId();
|
||||||
Optional<BluetoothLeBroadcastMetadata> metadata =
|
Optional<BluetoothLeBroadcastMetadata> metadata =
|
||||||
getMetadataMatchingByBroadcastId(
|
getMetadataMatchingByBroadcastId(
|
||||||
device, receiveState.getSourceId(), broadcastIdConnected);
|
device, receiveState.getSourceId(), broadcastIdPaused);
|
||||||
handleQrCodeWithUnsetBroadcastIdIfNeeded(metadata, receiveState);
|
handleQrCodeWithUnsetBroadcastIdIfNeeded(metadata, receiveState);
|
||||||
mBroadcastIdToPreferenceMap.compute(
|
mBroadcastIdToPreferenceMap.compute(
|
||||||
broadcastIdConnected,
|
broadcastIdPaused,
|
||||||
(k, existingPreference) -> {
|
(k, existingPreference) -> {
|
||||||
if (existingPreference == null) {
|
if (existingPreference == null) {
|
||||||
// No existing preference for this source even if it's already connected,
|
// No existing preference for this source even if it's already existed but
|
||||||
// add one and set initial state to SOURCE_PRESENT. This could happen
|
// currently paused, add one and set initial state to SOURCE_PRESENT. This
|
||||||
// because
|
// could happen because we retrieves the paused source during onStart() from
|
||||||
// we retrieves the connected source during onStart() from
|
// AudioStreamsHelper#getAllPausedSources() even before the source is
|
||||||
// AudioStreamsHelper#getAllPresentSources() even before the source is
|
|
||||||
// founded by scanning.
|
// founded by scanning.
|
||||||
return metadata.isPresent()
|
return metadata.isPresent()
|
||||||
? addNewPreference(
|
? addNewPreference(
|
||||||
@@ -580,56 +586,43 @@ public class AudioStreamsProgressCategoryController extends BasePreferenceContro
|
|||||||
mLeBroadcastAssistant.registerServiceCallBack(mExecutor, mBroadcastAssistantCallback);
|
mLeBroadcastAssistant.registerServiceCallBack(mExecutor, mBroadcastAssistantCallback);
|
||||||
mExecutor.execute(
|
mExecutor.execute(
|
||||||
() -> {
|
() -> {
|
||||||
// Handle QR code scan, display currently connected streams then start scanning
|
// Handle QR code scan, display currently streaming or paused streams then start
|
||||||
// sequentially
|
// scanning sequentially
|
||||||
handleSourceFromQrCodeIfExists();
|
handleSourceFromQrCodeIfExists();
|
||||||
Map<BluetoothDevice, List<BluetoothLeBroadcastReceiveState>> sources =
|
Map<BluetoothDevice, List<BluetoothLeBroadcastReceiveState>> sources =
|
||||||
mAudioStreamsHelper.getAllSourcesByDevice();
|
mAudioStreamsHelper.getAllSourcesByDevice();
|
||||||
Map<BluetoothDevice, List<BluetoothLeBroadcastReceiveState>> connectedSources =
|
getStreamSourcesByDevice(sources).forEach(
|
||||||
getConnectedSources(sources);
|
|
||||||
if (isAudioSharingHysteresisModeFixAvailable(mContext)) {
|
|
||||||
// With hysteresis mode, we prioritize showing connected sources first.
|
|
||||||
// If no connected sources are found, we then show present sources.
|
|
||||||
if (!connectedSources.isEmpty()) {
|
|
||||||
connectedSources.forEach(
|
|
||||||
(device, stateList) ->
|
(device, stateList) ->
|
||||||
stateList.forEach(
|
stateList.forEach(
|
||||||
state -> handleSourceConnected(device, state)));
|
state -> handleSourceStreaming(device, state)));
|
||||||
} else {
|
if (mHysteresisModeFixAvailable) {
|
||||||
Map<BluetoothDevice, List<BluetoothLeBroadcastReceiveState>>
|
getPausedSourcesByDevice(sources).forEach(
|
||||||
presentSources = getPresentSources(sources);
|
|
||||||
presentSources.forEach(
|
|
||||||
(device, stateList) ->
|
(device, stateList) ->
|
||||||
stateList.forEach(
|
stateList.forEach(
|
||||||
state -> handleSourcePresent(device, state)));
|
state -> handleSourcePaused(device, state)));
|
||||||
}
|
|
||||||
} else {
|
|
||||||
connectedSources.forEach(
|
|
||||||
(device, stateList) ->
|
|
||||||
stateList.forEach(
|
|
||||||
state -> handleSourceConnected(device, state)));
|
|
||||||
}
|
}
|
||||||
mLeBroadcastAssistant.startSearchingForSources(emptyList());
|
mLeBroadcastAssistant.startSearchingForSources(emptyList());
|
||||||
mMediaControlHelper.start();
|
mMediaControlHelper.start();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<BluetoothDevice, List<BluetoothLeBroadcastReceiveState>> getConnectedSources(
|
private Map<BluetoothDevice, List<BluetoothLeBroadcastReceiveState>> getStreamSourcesByDevice(
|
||||||
Map<BluetoothDevice, List<BluetoothLeBroadcastReceiveState>> sources) {
|
Map<BluetoothDevice, List<BluetoothLeBroadcastReceiveState>> sources) {
|
||||||
return sources.entrySet().stream()
|
return sources.entrySet().stream()
|
||||||
.filter(
|
.filter(
|
||||||
entry ->
|
entry ->
|
||||||
entry.getValue().stream().anyMatch(AudioStreamsHelper::isConnected))
|
entry.getValue().stream().anyMatch(
|
||||||
|
state -> getLocalSourceState(state) == STREAMING))
|
||||||
.collect(toMap(Map.Entry::getKey, Map.Entry::getValue));
|
.collect(toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<BluetoothDevice, List<BluetoothLeBroadcastReceiveState>> getPresentSources(
|
private Map<BluetoothDevice, List<BluetoothLeBroadcastReceiveState>> getPausedSourcesByDevice(
|
||||||
Map<BluetoothDevice, List<BluetoothLeBroadcastReceiveState>> sources) {
|
Map<BluetoothDevice, List<BluetoothLeBroadcastReceiveState>> sources) {
|
||||||
return sources.entrySet().stream()
|
return sources.entrySet().stream()
|
||||||
.filter(
|
.filter(
|
||||||
entry ->
|
entry ->
|
||||||
entry.getValue().stream()
|
entry.getValue().stream()
|
||||||
.anyMatch(AudioStreamsHelper::hasSourcePresent))
|
.anyMatch(state -> getLocalSourceState(state) == PAUSED))
|
||||||
.collect(toMap(Map.Entry::getKey, Map.Entry::getValue));
|
.collect(toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -742,8 +735,4 @@ public class AudioStreamsProgressCategoryController extends BasePreferenceContro
|
|||||||
dialog.dismiss();
|
dialog.dismiss();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isAudioSharingHysteresisModeFixAvailable(Context context) {
|
|
||||||
return BluetoothUtils.isAudioSharingHysteresisModeFixAvailable(context);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -46,6 +46,7 @@ import org.robolectric.RobolectricTestRunner;
|
|||||||
import org.robolectric.annotation.Config;
|
import org.robolectric.annotation.Config;
|
||||||
import org.robolectric.shadow.api.Shadow;
|
import org.robolectric.shadow.api.Shadow;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
@@ -143,9 +144,12 @@ public class BluetoothDetailsAudioSharingControllerTest extends BluetoothDetails
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
|
@EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
|
||||||
public void connected_hasConnectedBroadcastSource_showTwoPreference() {
|
public void connected_hasBroadcastSource_showTwoPreference() {
|
||||||
when(mCachedDevice.isConnectedLeAudioDevice()).thenReturn(true);
|
when(mCachedDevice.isConnectedLeAudioDevice()).thenReturn(true);
|
||||||
when(mCachedDevice.isActiveDevice(BluetoothProfile.LE_AUDIO)).thenReturn(false);
|
when(mCachedDevice.isActiveDevice(BluetoothProfile.LE_AUDIO)).thenReturn(false);
|
||||||
|
List<Long> bisSyncState = new ArrayList<>();
|
||||||
|
bisSyncState.add(1L);
|
||||||
|
when(mBroadcastReceiveState.getBisSyncState()).thenReturn(bisSyncState);
|
||||||
when(mLocalManager
|
when(mLocalManager
|
||||||
.getProfileManager()
|
.getProfileManager()
|
||||||
.getLeAudioBroadcastAssistantProfile()
|
.getLeAudioBroadcastAssistantProfile()
|
||||||
|
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package com.android.settings.connecteddevice.audiosharing.audiostreams;
|
package com.android.settings.connecteddevice.audiosharing.audiostreams;
|
||||||
|
|
||||||
|
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState.PAUSED;
|
||||||
|
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState.STREAMING;
|
||||||
import static com.android.settingslib.flags.Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX;
|
import static com.android.settingslib.flags.Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX;
|
||||||
import static com.android.settingslib.flags.Flags.FLAG_ENABLE_LE_AUDIO_SHARING;
|
import static com.android.settingslib.flags.Flags.FLAG_ENABLE_LE_AUDIO_SHARING;
|
||||||
|
|
||||||
@@ -71,6 +73,7 @@ import org.robolectric.shadow.api.Shadow;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
@@ -164,9 +167,9 @@ public class AudioStreamButtonControllerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDisplayPreference_sourceConnected_setDisconnectButton() {
|
public void testDisplayPreference_sourceStreaming_setDisconnectButton() {
|
||||||
when(mAudioStreamsHelper.getAllConnectedSources())
|
when(mAudioStreamsHelper.getConnectedBroadcastIdAndState(anyBoolean()))
|
||||||
.thenReturn(List.of(mBroadcastReceiveState));
|
.thenReturn(Map.of(BROADCAST_ID, STREAMING));
|
||||||
when(mBroadcastReceiveState.getBroadcastId()).thenReturn(BROADCAST_ID);
|
when(mBroadcastReceiveState.getBroadcastId()).thenReturn(BROADCAST_ID);
|
||||||
|
|
||||||
mController.displayPreference(mScreen);
|
mController.displayPreference(mScreen);
|
||||||
@@ -190,7 +193,8 @@ public class AudioStreamButtonControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDisplayPreference_sourceNotConnected_setConnectButton() {
|
public void testDisplayPreference_sourceNotConnected_setConnectButton() {
|
||||||
when(mAudioStreamsHelper.getAllConnectedSources()).thenReturn(Collections.emptyList());
|
when(mAudioStreamsHelper.getConnectedBroadcastIdAndState(anyBoolean()))
|
||||||
|
.thenReturn(Collections.emptyMap());
|
||||||
mController.setAudioStreamsRepositoryForTesting(mRepository);
|
mController.setAudioStreamsRepositoryForTesting(mRepository);
|
||||||
var metadataToRejoin = mock(BluetoothLeBroadcastMetadata.class);
|
var metadataToRejoin = mock(BluetoothLeBroadcastMetadata.class);
|
||||||
when(mRepository.getSavedMetadata(any(), anyInt())).thenReturn(metadataToRejoin);
|
when(mRepository.getSavedMetadata(any(), anyInt())).thenReturn(metadataToRejoin);
|
||||||
@@ -216,7 +220,8 @@ public class AudioStreamButtonControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCallback_onSourceRemoved_updateButton() {
|
public void testCallback_onSourceRemoved_updateButton() {
|
||||||
when(mAudioStreamsHelper.getAllConnectedSources()).thenReturn(Collections.emptyList());
|
when(mAudioStreamsHelper.getConnectedBroadcastIdAndState(anyBoolean()))
|
||||||
|
.thenReturn(Collections.emptyMap());
|
||||||
|
|
||||||
mController.displayPreference(mScreen);
|
mController.displayPreference(mScreen);
|
||||||
mController.mBroadcastAssistantCallback.onSourceRemoved(
|
mController.mBroadcastAssistantCallback.onSourceRemoved(
|
||||||
@@ -230,9 +235,8 @@ public class AudioStreamButtonControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCallback_onSourceRemovedFailed_updateButton() {
|
public void testCallback_onSourceRemovedFailed_updateButton() {
|
||||||
when(mAudioStreamsHelper.getAllConnectedSources())
|
when(mAudioStreamsHelper.getConnectedBroadcastIdAndState(anyBoolean()))
|
||||||
.thenReturn(List.of(mBroadcastReceiveState));
|
.thenReturn(Map.of(BROADCAST_ID, STREAMING));
|
||||||
when(mBroadcastReceiveState.getBroadcastId()).thenReturn(BROADCAST_ID);
|
|
||||||
|
|
||||||
mController.displayPreference(mScreen);
|
mController.displayPreference(mScreen);
|
||||||
mController.mBroadcastAssistantCallback.onSourceRemoveFailed(
|
mController.mBroadcastAssistantCallback.onSourceRemoveFailed(
|
||||||
@@ -250,9 +254,8 @@ public class AudioStreamButtonControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCallback_onReceiveStateChanged_updateButton() {
|
public void testCallback_onReceiveStateChanged_updateButton() {
|
||||||
when(mAudioStreamsHelper.getAllConnectedSources())
|
when(mAudioStreamsHelper.getConnectedBroadcastIdAndState(anyBoolean()))
|
||||||
.thenReturn(List.of(mBroadcastReceiveState));
|
.thenReturn(Map.of(BROADCAST_ID, STREAMING));
|
||||||
when(mBroadcastReceiveState.getBroadcastId()).thenReturn(BROADCAST_ID);
|
|
||||||
BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class);
|
BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class);
|
||||||
List<Long> bisSyncState = new ArrayList<>();
|
List<Long> bisSyncState = new ArrayList<>();
|
||||||
bisSyncState.add(1L);
|
bisSyncState.add(1L);
|
||||||
@@ -273,7 +276,7 @@ public class AudioStreamButtonControllerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCallback_onReceiveStateChangedWithSourcePresent_updateButton() {
|
public void testCallback_onReceiveStateChangedWithSourcePaused_updateButton() {
|
||||||
mSetFlagsRule.enableFlags(FLAG_ENABLE_LE_AUDIO_SHARING);
|
mSetFlagsRule.enableFlags(FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
mSetFlagsRule.enableFlags(FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
|
mSetFlagsRule.enableFlags(FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
|
||||||
String address = "11:22:33:44:55:66";
|
String address = "11:22:33:44:55:66";
|
||||||
@@ -284,13 +287,16 @@ public class AudioStreamButtonControllerTest {
|
|||||||
when(mSourceDevice.getAddress()).thenReturn(address);
|
when(mSourceDevice.getAddress()).thenReturn(address);
|
||||||
List<Long> bisSyncState = new ArrayList<>();
|
List<Long> bisSyncState = new ArrayList<>();
|
||||||
when(state.getBisSyncState()).thenReturn(bisSyncState);
|
when(state.getBisSyncState()).thenReturn(bisSyncState);
|
||||||
when(mAudioStreamsHelper.getAllPresentSources()).thenReturn(List.of(state));
|
when(mAudioStreamsHelper.getConnectedBroadcastIdAndState(anyBoolean()))
|
||||||
|
.thenReturn(Map.of(BROADCAST_ID, PAUSED));
|
||||||
|
// Create new controller to enable hysteresis mode
|
||||||
|
mController = new AudioStreamButtonController(mContext, KEY);
|
||||||
|
mController.init(BROADCAST_ID);
|
||||||
mController.displayPreference(mScreen);
|
mController.displayPreference(mScreen);
|
||||||
mController.mBroadcastAssistantCallback.onReceiveStateChanged(
|
mController.mBroadcastAssistantCallback.onReceiveStateChanged(
|
||||||
mock(BluetoothDevice.class), /* sourceId= */ 0, state);
|
mock(BluetoothDevice.class), /* sourceId= */ 0, state);
|
||||||
|
|
||||||
verify(mFeatureFactory.metricsFeatureProvider, never())
|
verify(mFeatureFactory.metricsFeatureProvider)
|
||||||
.action(any(), eq(SettingsEnums.ACTION_AUDIO_STREAM_JOIN_SUCCEED), anyInt());
|
.action(any(), eq(SettingsEnums.ACTION_AUDIO_STREAM_JOIN_SUCCEED), anyInt());
|
||||||
|
|
||||||
// Called twice, once in displayPreference, the other one in callback
|
// Called twice, once in displayPreference, the other one in callback
|
||||||
@@ -302,7 +308,8 @@ public class AudioStreamButtonControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCallback_onSourceAddFailed_updateButton() {
|
public void testCallback_onSourceAddFailed_updateButton() {
|
||||||
when(mAudioStreamsHelper.getAllConnectedSources()).thenReturn(Collections.emptyList());
|
when(mAudioStreamsHelper.getConnectedBroadcastIdAndState(anyBoolean()))
|
||||||
|
.thenReturn(Collections.emptyMap());
|
||||||
|
|
||||||
mController.displayPreference(mScreen);
|
mController.displayPreference(mScreen);
|
||||||
mController.mBroadcastAssistantCallback.onSourceAddFailed(
|
mController.mBroadcastAssistantCallback.onSourceAddFailed(
|
||||||
@@ -321,7 +328,8 @@ public class AudioStreamButtonControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCallback_onSourceLost_updateButton() {
|
public void testCallback_onSourceLost_updateButton() {
|
||||||
when(mAudioStreamsHelper.getAllConnectedSources()).thenReturn(Collections.emptyList());
|
when(mAudioStreamsHelper.getConnectedBroadcastIdAndState(anyBoolean()))
|
||||||
|
.thenReturn(Collections.emptyMap());
|
||||||
|
|
||||||
mController.displayPreference(mScreen);
|
mController.displayPreference(mScreen);
|
||||||
mController.mBroadcastAssistantCallback.onSourceLost(/* broadcastId= */ 0);
|
mController.mBroadcastAssistantCallback.onSourceLost(/* broadcastId= */ 0);
|
||||||
|
@@ -19,10 +19,13 @@ package com.android.settings.connecteddevice.audiosharing.audiostreams;
|
|||||||
import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamHeaderController.AUDIO_STREAM_HEADER_LISTENING_NOW_SUMMARY;
|
import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamHeaderController.AUDIO_STREAM_HEADER_LISTENING_NOW_SUMMARY;
|
||||||
import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamHeaderController.AUDIO_STREAM_HEADER_NOT_LISTENING_SUMMARY;
|
import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamHeaderController.AUDIO_STREAM_HEADER_NOT_LISTENING_SUMMARY;
|
||||||
import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamHeaderController.AUDIO_STREAM_HEADER_PRESENT_NOW_SUMMARY;
|
import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamHeaderController.AUDIO_STREAM_HEADER_PRESENT_NOW_SUMMARY;
|
||||||
|
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState.PAUSED;
|
||||||
|
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState.STREAMING;
|
||||||
import static com.android.settingslib.flags.Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX;
|
import static com.android.settingslib.flags.Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX;
|
||||||
import static com.android.settingslib.flags.Flags.FLAG_ENABLE_LE_AUDIO_SHARING;
|
import static com.android.settingslib.flags.Flags.FLAG_ENABLE_LE_AUDIO_SHARING;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||||
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.times;
|
import static org.mockito.Mockito.times;
|
||||||
@@ -66,6 +69,7 @@ import org.robolectric.shadow.api.Shadow;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
@@ -160,10 +164,9 @@ public class AudioStreamHeaderControllerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDisplayPreference_sourceConnected_setSummary() {
|
public void testDisplayPreference_sourceStreaming_setSummary() {
|
||||||
when(mAudioStreamsHelper.getAllConnectedSources())
|
when(mAudioStreamsHelper.getConnectedBroadcastIdAndState(anyBoolean()))
|
||||||
.thenReturn(List.of(mBroadcastReceiveState));
|
.thenReturn(Map.of(BROADCAST_ID, STREAMING));
|
||||||
when(mBroadcastReceiveState.getBroadcastId()).thenReturn(BROADCAST_ID);
|
|
||||||
|
|
||||||
mController.displayPreference(mScreen);
|
mController.displayPreference(mScreen);
|
||||||
|
|
||||||
@@ -176,8 +179,9 @@ public class AudioStreamHeaderControllerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDisplayPreference_sourceNotConnected_setSummary() {
|
public void testDisplayPreference_sourceNotStreaming_setSummary() {
|
||||||
when(mAudioStreamsHelper.getAllConnectedSources()).thenReturn(Collections.emptyList());
|
when(mAudioStreamsHelper.getConnectedBroadcastIdAndState(anyBoolean()))
|
||||||
|
.thenReturn(Collections.emptyMap());
|
||||||
|
|
||||||
mController.displayPreference(mScreen);
|
mController.displayPreference(mScreen);
|
||||||
|
|
||||||
@@ -189,18 +193,14 @@ public class AudioStreamHeaderControllerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDisplayPreference_sourcePresent_setSummary() {
|
public void testDisplayPreference_sourcePaused_setSummary() {
|
||||||
mSetFlagsRule.enableFlags(FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
|
mSetFlagsRule.enableFlags(FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
|
||||||
String address = "11:22:33:44:55:66";
|
when(mAudioStreamsHelper.getConnectedBroadcastIdAndState(anyBoolean()))
|
||||||
|
.thenReturn(Map.of(BROADCAST_ID, PAUSED));
|
||||||
when(mBroadcastReceiveState.getBroadcastId()).thenReturn(BROADCAST_ID);
|
|
||||||
when(mBroadcastReceiveState.getSourceDevice()).thenReturn(mBluetoothDevice);
|
|
||||||
when(mBluetoothDevice.getAddress()).thenReturn(address);
|
|
||||||
List<Long> bisSyncState = new ArrayList<>();
|
|
||||||
when(mBroadcastReceiveState.getBisSyncState()).thenReturn(bisSyncState);
|
|
||||||
when(mAudioStreamsHelper.getAllPresentSources())
|
|
||||||
.thenReturn(List.of(mBroadcastReceiveState));
|
|
||||||
|
|
||||||
|
// Create new controller to enable hysteresis mode
|
||||||
|
mController = new AudioStreamHeaderController(mContext, KEY);
|
||||||
|
mController.init(mFragment, BROADCAST_NAME, BROADCAST_ID);
|
||||||
mController.displayPreference(mScreen);
|
mController.displayPreference(mScreen);
|
||||||
|
|
||||||
verify(mHeaderController).setLabel(BROADCAST_NAME);
|
verify(mHeaderController).setLabel(BROADCAST_NAME);
|
||||||
@@ -212,10 +212,10 @@ public class AudioStreamHeaderControllerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDisplayPreference_sourceNotPresent_setSummary() {
|
public void testDisplayPreference_sourceNotPaused_setSummary() {
|
||||||
mSetFlagsRule.enableFlags(FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
|
mSetFlagsRule.enableFlags(FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
|
||||||
|
when(mAudioStreamsHelper.getConnectedBroadcastIdAndState(anyBoolean()))
|
||||||
when(mAudioStreamsHelper.getAllPresentSources()).thenReturn(Collections.emptyList());
|
.thenReturn(Collections.emptyMap());
|
||||||
|
|
||||||
mController.displayPreference(mScreen);
|
mController.displayPreference(mScreen);
|
||||||
|
|
||||||
@@ -228,7 +228,8 @@ public class AudioStreamHeaderControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCallback_onSourceRemoved_updateButton() {
|
public void testCallback_onSourceRemoved_updateButton() {
|
||||||
when(mAudioStreamsHelper.getAllConnectedSources()).thenReturn(Collections.emptyList());
|
when(mAudioStreamsHelper.getConnectedBroadcastIdAndState(anyBoolean()))
|
||||||
|
.thenReturn(Collections.emptyMap());
|
||||||
|
|
||||||
mController.displayPreference(mScreen);
|
mController.displayPreference(mScreen);
|
||||||
mController.mBroadcastAssistantCallback.onSourceRemoved(
|
mController.mBroadcastAssistantCallback.onSourceRemoved(
|
||||||
@@ -241,7 +242,8 @@ public class AudioStreamHeaderControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCallback_onSourceLost_updateButton() {
|
public void testCallback_onSourceLost_updateButton() {
|
||||||
when(mAudioStreamsHelper.getAllConnectedSources()).thenReturn(Collections.emptyList());
|
when(mAudioStreamsHelper.getConnectedBroadcastIdAndState(anyBoolean()))
|
||||||
|
.thenReturn(Collections.emptyMap());
|
||||||
|
|
||||||
mController.displayPreference(mScreen);
|
mController.displayPreference(mScreen);
|
||||||
mController.mBroadcastAssistantCallback.onSourceLost(/* broadcastId= */ 1);
|
mController.mBroadcastAssistantCallback.onSourceLost(/* broadcastId= */ 1);
|
||||||
@@ -253,8 +255,8 @@ public class AudioStreamHeaderControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCallback_onReceiveStateChanged_updateButton() {
|
public void testCallback_onReceiveStateChanged_updateButton() {
|
||||||
when(mAudioStreamsHelper.getAllConnectedSources())
|
when(mAudioStreamsHelper.getConnectedBroadcastIdAndState(anyBoolean()))
|
||||||
.thenReturn(List.of(mBroadcastReceiveState));
|
.thenReturn(Map.of(BROADCAST_ID, STREAMING));
|
||||||
when(mBroadcastReceiveState.getBroadcastId()).thenReturn(BROADCAST_ID);
|
when(mBroadcastReceiveState.getBroadcastId()).thenReturn(BROADCAST_ID);
|
||||||
BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class);
|
BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class);
|
||||||
List<Long> bisSyncState = new ArrayList<>();
|
List<Long> bisSyncState = new ArrayList<>();
|
||||||
@@ -272,17 +274,20 @@ public class AudioStreamHeaderControllerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCallback_onReceiveStateChangedWithSourcePresent_updateButton() {
|
public void testCallback_onReceiveStateChangedWithSourcePaused_updateButton() {
|
||||||
mSetFlagsRule.enableFlags(FLAG_ENABLE_LE_AUDIO_SHARING);
|
mSetFlagsRule.enableFlags(FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
mSetFlagsRule.enableFlags(FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
|
mSetFlagsRule.enableFlags(FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
|
||||||
String address = "11:22:33:44:55:66";
|
String address = "11:22:33:44:55:66";
|
||||||
|
|
||||||
when(mAudioStreamsHelper.getAllPresentSources())
|
when(mAudioStreamsHelper.getConnectedBroadcastIdAndState(anyBoolean()))
|
||||||
.thenReturn(List.of(mBroadcastReceiveState));
|
.thenReturn(Map.of(BROADCAST_ID, PAUSED));
|
||||||
when(mBroadcastReceiveState.getBroadcastId()).thenReturn(BROADCAST_ID);
|
when(mBroadcastReceiveState.getBroadcastId()).thenReturn(BROADCAST_ID);
|
||||||
when(mBroadcastReceiveState.getSourceDevice()).thenReturn(mBluetoothDevice);
|
when(mBroadcastReceiveState.getSourceDevice()).thenReturn(mBluetoothDevice);
|
||||||
when(mBluetoothDevice.getAddress()).thenReturn(address);
|
when(mBluetoothDevice.getAddress()).thenReturn(address);
|
||||||
|
|
||||||
|
// Create new controller to enable hysteresis mode
|
||||||
|
mController = new AudioStreamHeaderController(mContext, KEY);
|
||||||
|
mController.init(mFragment, BROADCAST_NAME, BROADCAST_ID);
|
||||||
mController.displayPreference(mScreen);
|
mController.displayPreference(mScreen);
|
||||||
mController.mBroadcastAssistantCallback.onReceiveStateChanged(
|
mController.mBroadcastAssistantCallback.onReceiveStateChanged(
|
||||||
mock(BluetoothDevice.class), /* sourceId= */ 0, mBroadcastReceiveState);
|
mock(BluetoothDevice.class), /* sourceId= */ 0, mBroadcastReceiveState);
|
||||||
|
@@ -19,6 +19,8 @@ package com.android.settings.connecteddevice.audiosharing.audiostreams;
|
|||||||
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
|
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
|
||||||
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
|
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
|
||||||
|
|
||||||
|
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState.PAUSED;
|
||||||
|
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState.STREAMING;
|
||||||
import static com.android.settingslib.flags.Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX;
|
import static com.android.settingslib.flags.Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX;
|
||||||
import static com.android.settingslib.flags.Flags.FLAG_ENABLE_LE_AUDIO_SHARING;
|
import static com.android.settingslib.flags.Flags.FLAG_ENABLE_LE_AUDIO_SHARING;
|
||||||
|
|
||||||
@@ -149,11 +151,14 @@ public class AudioStreamsHelperTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void removeSource_noConnectedSource_doNothing() {
|
public void removeSource_noConnectedSource_doNothing() {
|
||||||
|
String address = "11:22:33:44:55:66";
|
||||||
List<BluetoothDevice> devices = new ArrayList<>();
|
List<BluetoothDevice> devices = new ArrayList<>();
|
||||||
devices.add(mDevice);
|
devices.add(mDevice);
|
||||||
when(mAssistant.getAllConnectedDevices()).thenReturn(devices);
|
when(mAssistant.getAllConnectedDevices()).thenReturn(devices);
|
||||||
BluetoothLeBroadcastReceiveState source = mock(BluetoothLeBroadcastReceiveState.class);
|
BluetoothLeBroadcastReceiveState source = mock(BluetoothLeBroadcastReceiveState.class);
|
||||||
when(source.getBroadcastId()).thenReturn(BROADCAST_ID_2);
|
when(source.getBroadcastId()).thenReturn(BROADCAST_ID_2);
|
||||||
|
when(source.getSourceDevice()).thenReturn(mSourceDevice);
|
||||||
|
when(mSourceDevice.getAddress()).thenReturn(address);
|
||||||
when(mDeviceManager.findDevice(any())).thenReturn(mCachedDevice);
|
when(mDeviceManager.findDevice(any())).thenReturn(mCachedDevice);
|
||||||
when(mCachedDevice.getDevice()).thenReturn(mDevice);
|
when(mCachedDevice.getDevice()).thenReturn(mDevice);
|
||||||
when(mCachedDevice.getGroupId()).thenReturn(GROUP_ID);
|
when(mCachedDevice.getGroupId()).thenReturn(GROUP_ID);
|
||||||
@@ -214,15 +219,16 @@ public class AudioStreamsHelperTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getAllConnectedSources_noAssistant() {
|
public void getConnectedBroadcastIdAndState_noAssistant() {
|
||||||
when(mLocalBluetoothProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(null);
|
when(mLocalBluetoothProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(null);
|
||||||
mHelper = new AudioStreamsHelper(mLocalBluetoothManager);
|
mHelper = new AudioStreamsHelper(mLocalBluetoothManager);
|
||||||
|
|
||||||
assertThat(mHelper.getAllConnectedSources()).isEmpty();
|
assertThat(mHelper.getConnectedBroadcastIdAndState(/* hysteresisModeFixAvailable= */
|
||||||
|
false)).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getAllConnectedSources_returnSource() {
|
public void getConnectedBroadcastIdAndState_returnStreamingSource() {
|
||||||
List<BluetoothDevice> devices = new ArrayList<>();
|
List<BluetoothDevice> devices = new ArrayList<>();
|
||||||
devices.add(mDevice);
|
devices.add(mDevice);
|
||||||
when(mAssistant.getAllConnectedDevices()).thenReturn(devices);
|
when(mAssistant.getAllConnectedDevices()).thenReturn(devices);
|
||||||
@@ -234,14 +240,15 @@ public class AudioStreamsHelperTest {
|
|||||||
List<Long> bisSyncState = new ArrayList<>();
|
List<Long> bisSyncState = new ArrayList<>();
|
||||||
bisSyncState.add(1L);
|
bisSyncState.add(1L);
|
||||||
when(source.getBisSyncState()).thenReturn(bisSyncState);
|
when(source.getBisSyncState()).thenReturn(bisSyncState);
|
||||||
|
when(source.getBroadcastId()).thenReturn(BROADCAST_ID_1);
|
||||||
|
|
||||||
var list = mHelper.getAllConnectedSources();
|
var map = mHelper.getConnectedBroadcastIdAndState(/* hysteresisModeFixAvailable= */ false);
|
||||||
assertThat(list).isNotEmpty();
|
assertThat(map).isNotEmpty();
|
||||||
assertThat(list.get(0)).isEqualTo(source);
|
assertThat(map.get(BROADCAST_ID_1)).isEqualTo(STREAMING);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getAllPresentSources_noSource() {
|
public void getConnectedBroadcastIdAndState_noSource() {
|
||||||
mSetFlagsRule.enableFlags(FLAG_ENABLE_LE_AUDIO_SHARING);
|
mSetFlagsRule.enableFlags(FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
mSetFlagsRule.enableFlags(FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
|
mSetFlagsRule.enableFlags(FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
|
||||||
|
|
||||||
@@ -259,12 +266,12 @@ public class AudioStreamsHelperTest {
|
|||||||
when(source.getSourceDevice()).thenReturn(mSourceDevice);
|
when(source.getSourceDevice()).thenReturn(mSourceDevice);
|
||||||
when(mSourceDevice.getAddress()).thenReturn(address);
|
when(mSourceDevice.getAddress()).thenReturn(address);
|
||||||
|
|
||||||
var list = mHelper.getAllPresentSources();
|
var map = mHelper.getConnectedBroadcastIdAndState(/* hysteresisModeFixAvailable= */ true);
|
||||||
assertThat(list).isEmpty();
|
assertThat(map).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getAllPresentSources_returnSource() {
|
public void getConnectedBroadcastIdAndState_returnPausedSource() {
|
||||||
mSetFlagsRule.enableFlags(FLAG_ENABLE_LE_AUDIO_SHARING);
|
mSetFlagsRule.enableFlags(FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
mSetFlagsRule.enableFlags(FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
|
mSetFlagsRule.enableFlags(FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
|
||||||
String address = "11:22:33:44:55:66";
|
String address = "11:22:33:44:55:66";
|
||||||
@@ -282,10 +289,11 @@ public class AudioStreamsHelperTest {
|
|||||||
when(mSourceDevice.getAddress()).thenReturn(address);
|
when(mSourceDevice.getAddress()).thenReturn(address);
|
||||||
List<Long> bisSyncState = new ArrayList<>();
|
List<Long> bisSyncState = new ArrayList<>();
|
||||||
when(source.getBisSyncState()).thenReturn(bisSyncState);
|
when(source.getBisSyncState()).thenReturn(bisSyncState);
|
||||||
|
when(source.getBroadcastId()).thenReturn(BROADCAST_ID_1);
|
||||||
|
|
||||||
var list = mHelper.getAllPresentSources();
|
var map = mHelper.getConnectedBroadcastIdAndState(/* hysteresisModeFixAvailable= */ true);
|
||||||
assertThat(list).isNotEmpty();
|
assertThat(map).isNotEmpty();
|
||||||
assertThat(list.get(0)).isEqualTo(source);
|
assertThat(map.get(BROADCAST_ID_1)).isEqualTo(PAUSED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@@ -77,7 +77,7 @@ public class AudioStreamsProgressCategoryCallbackTest {
|
|||||||
BluetoothStatusCodes.FEATURE_SUPPORTED);
|
BluetoothStatusCodes.FEATURE_SUPPORTED);
|
||||||
shadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
|
shadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
|
||||||
BluetoothStatusCodes.FEATURE_SUPPORTED);
|
BluetoothStatusCodes.FEATURE_SUPPORTED);
|
||||||
mCallback = new AudioStreamsProgressCategoryCallback(mContext, mController);
|
mCallback = new AudioStreamsProgressCategoryCallback(mController);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -87,7 +87,7 @@ public class AudioStreamsProgressCategoryCallbackTest {
|
|||||||
when(mState.getBisSyncState()).thenReturn(bisSyncState);
|
when(mState.getBisSyncState()).thenReturn(bisSyncState);
|
||||||
mCallback.onReceiveStateChanged(mDevice, /* sourceId= */ 0, mState);
|
mCallback.onReceiveStateChanged(mDevice, /* sourceId= */ 0, mState);
|
||||||
|
|
||||||
verify(mController).handleSourceConnected(any(), any());
|
verify(mController).handleSourceStreaming(any(), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -102,7 +102,7 @@ public class AudioStreamsProgressCategoryCallbackTest {
|
|||||||
when(mSourceDevice.getAddress()).thenReturn(address);
|
when(mSourceDevice.getAddress()).thenReturn(address);
|
||||||
mCallback.onReceiveStateChanged(mDevice, /* sourceId= */ 0, mState);
|
mCallback.onReceiveStateChanged(mDevice, /* sourceId= */ 0, mState);
|
||||||
|
|
||||||
verify(mController).handleSourcePresent(any(), any());
|
verify(mController).handleSourcePaused(any(), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@@ -25,6 +25,7 @@ import static com.android.settings.connecteddevice.audiosharing.audiostreams.Aud
|
|||||||
import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamsProgressCategoryController.AudioStreamState.WAIT_FOR_SYNC;
|
import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamsProgressCategoryController.AudioStreamState.WAIT_FOR_SYNC;
|
||||||
import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamsProgressCategoryController.UNSET_BROADCAST_ID;
|
import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamsProgressCategoryController.UNSET_BROADCAST_ID;
|
||||||
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
|
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
|
||||||
|
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState.STREAMING;
|
||||||
import static com.android.settingslib.flags.Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX;
|
import static com.android.settingslib.flags.Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX;
|
||||||
import static com.android.settingslib.flags.Flags.FLAG_ENABLE_LE_AUDIO_SHARING;
|
import static com.android.settingslib.flags.Flags.FLAG_ENABLE_LE_AUDIO_SHARING;
|
||||||
|
|
||||||
@@ -355,7 +356,7 @@ public class AudioStreamsProgressCategoryControllerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOnStart_handleSourceAlreadyConnected_useNameFromMetadata() {
|
public void testOnStart_handleSourceAlreadyStreaming_useNameFromMetadata() {
|
||||||
// Setup a device
|
// Setup a device
|
||||||
ShadowAudioStreamsHelper.setCachedBluetoothDeviceInSharingOrLeConnected(mDevice);
|
ShadowAudioStreamsHelper.setCachedBluetoothDeviceInSharingOrLeConnected(mDevice);
|
||||||
|
|
||||||
@@ -665,8 +666,8 @@ public class AudioStreamsProgressCategoryControllerTest {
|
|||||||
shadowOf(Looper.getMainLooper()).idle();
|
shadowOf(Looper.getMainLooper()).idle();
|
||||||
|
|
||||||
// A new source found is lost, but the source is still connected
|
// A new source found is lost, but the source is still connected
|
||||||
BluetoothLeBroadcastReceiveState connected = createConnectedMock(NEWLY_FOUND_BROADCAST_ID);
|
when(mAudioStreamsHelper.getConnectedBroadcastIdAndState(anyBoolean())).thenReturn(
|
||||||
when(mAudioStreamsHelper.getAllConnectedSources()).thenReturn(ImmutableList.of(connected));
|
Map.of(NEWLY_FOUND_BROADCAST_ID, STREAMING));
|
||||||
mController.handleSourceLost(NEWLY_FOUND_BROADCAST_ID);
|
mController.handleSourceLost(NEWLY_FOUND_BROADCAST_ID);
|
||||||
shadowOf(Looper.getMainLooper()).idle();
|
shadowOf(Looper.getMainLooper()).idle();
|
||||||
|
|
||||||
@@ -819,13 +820,15 @@ public class AudioStreamsProgressCategoryControllerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHandleSourcePresent_updateState() {
|
public void testHandleSourcePaused_updateState() {
|
||||||
mSetFlagsRule.enableFlags(FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
|
mSetFlagsRule.enableFlags(FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
|
||||||
String address = "11:22:33:44:55:66";
|
String address = "11:22:33:44:55:66";
|
||||||
|
|
||||||
// Setup a device
|
// Setup a device
|
||||||
ShadowAudioStreamsHelper.setCachedBluetoothDeviceInSharingOrLeConnected(mDevice);
|
ShadowAudioStreamsHelper.setCachedBluetoothDeviceInSharingOrLeConnected(mDevice);
|
||||||
|
|
||||||
|
// Create new controller to enable hysteresis mode
|
||||||
|
mController = spy(new TestController(mContext, KEY));
|
||||||
// Setup mPreference so it's not null
|
// Setup mPreference so it's not null
|
||||||
mController.displayPreference(mScreen);
|
mController.displayPreference(mScreen);
|
||||||
|
|
||||||
@@ -844,7 +847,7 @@ public class AudioStreamsProgressCategoryControllerTest {
|
|||||||
when(receiveState.getBisSyncState()).thenReturn(bisSyncState);
|
when(receiveState.getBisSyncState()).thenReturn(bisSyncState);
|
||||||
|
|
||||||
// The new found source is identified as failed to connect
|
// The new found source is identified as failed to connect
|
||||||
mController.handleSourcePresent(mSourceDevice, receiveState);
|
mController.handleSourcePaused(mSourceDevice, receiveState);
|
||||||
shadowOf(Looper.getMainLooper()).idle();
|
shadowOf(Looper.getMainLooper()).idle();
|
||||||
|
|
||||||
ArgumentCaptor<AudioStreamPreference> preference =
|
ArgumentCaptor<AudioStreamPreference> preference =
|
||||||
|
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package com.android.settings.connecteddevice.audiosharing.audiostreams.testshadows;
|
package com.android.settings.connecteddevice.audiosharing.audiostreams.testshadows;
|
||||||
|
|
||||||
|
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState;
|
||||||
|
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.bluetooth.BluetoothLeBroadcastMetadata;
|
import android.bluetooth.BluetoothLeBroadcastMetadata;
|
||||||
import android.bluetooth.BluetoothLeBroadcastReceiveState;
|
import android.bluetooth.BluetoothLeBroadcastReceiveState;
|
||||||
@@ -57,8 +59,9 @@ public class ShadowAudioStreamsHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Implementation
|
@Implementation
|
||||||
public List<BluetoothLeBroadcastReceiveState> getAllConnectedSources() {
|
public Map<Integer, LocalBluetoothLeBroadcastSourceState> getConnectedBroadcastIdAndState(
|
||||||
return sMockHelper.getAllConnectedSources();
|
boolean hysteresisModeFixAvailable) {
|
||||||
|
return sMockHelper.getConnectedBroadcastIdAndState(hysteresisModeFixAvailable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Implementation
|
@Implementation
|
||||||
@@ -66,11 +69,6 @@ public class ShadowAudioStreamsHelper {
|
|||||||
return sMockHelper.getAllSourcesByDevice();
|
return sMockHelper.getAllSourcesByDevice();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Implementation
|
|
||||||
public List<BluetoothLeBroadcastReceiveState> getAllPresentSources() {
|
|
||||||
return sMockHelper.getAllPresentSources();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Gets {@link CachedBluetoothDevice} in sharing or le connected */
|
/** Gets {@link CachedBluetoothDevice} in sharing or le connected */
|
||||||
@Implementation
|
@Implementation
|
||||||
public static Optional<CachedBluetoothDevice> getCachedBluetoothDeviceInSharingOrLeConnected(
|
public static Optional<CachedBluetoothDevice> getCachedBluetoothDeviceInSharingOrLeConnected(
|
||||||
|
Reference in New Issue
Block a user