Loading res/values/strings.xml +2 −0 Original line number Diff line number Diff line Loading @@ -13579,6 +13579,8 @@ <string name="audio_streams_dialog_cannot_play">Can\u0027t play this audio stream on <xliff:g example="LE headset" id="device_name">%1$s</xliff:g>.</string> <!-- The preference summary when add source succeed [CHAR LIMIT=NONE] --> <string name="audio_streams_listening_now">Listening now</string> <!-- The preference summary when source is present on sinks [CHAR LIMIT=NONE] --> <string name="audio_streams_present_now">Paused by host</string> <!-- Le audio streams service notification leave broadcast text [CHAR LIMIT=NONE] --> <string name="audio_streams_media_service_notification_leave_broadcast_text">Stop listening</string> <!-- Le audio streams no le device dialog title [CHAR LIMIT=NONE] --> src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamButtonController.java +20 −6 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.settings.connecteddevice.audiosharing.audiostreams; import static com.android.settingslib.flags.Flags.audioSharingHysteresisModeFix; import android.app.settings.SettingsEnums; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothLeBroadcastAssistant; Loading @@ -41,6 +43,7 @@ import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.utils.ThreadUtils; import com.android.settingslib.widget.ActionButtonsPreference; import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.Executors; Loading Loading @@ -73,14 +76,20 @@ public class AudioStreamButtonController extends BasePreferenceController int sourceId, BluetoothLeBroadcastReceiveState state) { super.onReceiveStateChanged(sink, sourceId, state); if (AudioStreamsHelper.isConnected(state)) { boolean shouldUpdateButton = audioSharingHysteresisModeFix() ? AudioStreamsHelper.hasSourcePresent(state) : AudioStreamsHelper.isConnected(state); if (shouldUpdateButton) { updateButton(); if (AudioStreamsHelper.isConnected(state)) { mMetricsFeatureProvider.action( mContext, SettingsEnums.ACTION_AUDIO_STREAM_JOIN_SUCCEED, SOURCE_ORIGIN_REPOSITORY); } } } @Override public void onSourceAddFailed( Loading Loading @@ -146,8 +155,13 @@ public class AudioStreamButtonController extends BasePreferenceController Log.w(TAG, "updateButton(): preference is null!"); return; } List<BluetoothLeBroadcastReceiveState> sources = audioSharingHysteresisModeFix() ? mAudioStreamsHelper.getAllPresentSources() : mAudioStreamsHelper.getAllConnectedSources(); boolean isConnected = mAudioStreamsHelper.getAllConnectedSources().stream() sources.stream() .map(BluetoothLeBroadcastReceiveState::getBroadcastId) .anyMatch(connectedBroadcastId -> connectedBroadcastId == mBroadcastId); Loading src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamHeaderController.java +34 −4 Original line number Diff line number Diff line Loading @@ -16,6 +16,10 @@ package com.android.settings.connecteddevice.audiosharing.audiostreams; import static com.android.settingslib.flags.Flags.audioSharingHysteresisModeFix; import static java.util.stream.Collectors.toList; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothLeBroadcastAssistant; import android.bluetooth.BluetoothLeBroadcastReceiveState; Loading Loading @@ -48,6 +52,8 @@ public class AudioStreamHeaderController extends BasePreferenceController static final int AUDIO_STREAM_HEADER_LISTENING_NOW_SUMMARY = R.string.audio_streams_listening_now; static final int AUDIO_STREAM_HEADER_PRESENT_NOW_SUMMARY = R.string.audio_streams_present_now; @VisibleForTesting static final String AUDIO_STREAM_HEADER_NOT_LISTENING_SUMMARY = ""; private static final String TAG = "AudioStreamHeaderController"; private static final String KEY = "audio_stream_header"; Loading Loading @@ -80,6 +86,10 @@ public class AudioStreamHeaderController extends BasePreferenceController updateSummary(); mAudioStreamsHelper.startMediaService( mContext, mBroadcastId, mBroadcastName); } else if (audioSharingHysteresisModeFix() && AudioStreamsHelper.hasSourcePresent(state)) { // if source present but not connected, only update the summary updateSummary(); } } }; Loading Loading @@ -140,8 +150,27 @@ public class AudioStreamHeaderController extends BasePreferenceController var unused = ThreadUtils.postOnBackgroundThread( () -> { var connectedSourceList = mAudioStreamsHelper.getAllPresentSources().stream() .filter( state -> (state.getBroadcastId() == mBroadcastId)) .collect(toList()); var latestSummary = mAudioStreamsHelper.getAllConnectedSources().stream() 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) Loading @@ -152,6 +181,7 @@ public class AudioStreamHeaderController extends BasePreferenceController ? mContext.getString( AUDIO_STREAM_HEADER_LISTENING_NOW_SUMMARY) : AUDIO_STREAM_HEADER_NOT_LISTENING_SUMMARY; ThreadUtils.postOnMainThread( () -> { if (mHeaderController != null) { Loading src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamStateHandler.java +8 −2 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ package com.android.settings.connecteddevice.audiosharing.audiostreams; import static android.text.Spanned.SPAN_EXCLUSIVE_INCLUSIVE; import static com.android.settingslib.flags.Flags.audioSharingHysteresisModeFix; import android.os.Handler; import android.os.Looper; import android.text.SpannableString; Loading Loading @@ -94,8 +96,12 @@ class AudioStreamStateHandler { } preference.setIsConnected( newState == AudioStreamsProgressCategoryController.AudioStreamState .SOURCE_ADDED); == AudioStreamsProgressCategoryController .AudioStreamState.SOURCE_ADDED || (audioSharingHysteresisModeFix() && newState == AudioStreamsProgressCategoryController .AudioStreamState.SOURCE_PRESENT)); preference.setOnPreferenceClickListener(getOnClickListener(controller)); }); } Loading src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsHelper.java +37 −3 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ 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_TITLE; import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamMediaService.DEVICES; import static com.android.settingslib.flags.Flags.audioSharingHysteresisModeFix; import static java.util.Collections.emptyList; Loading Loading @@ -63,6 +64,12 @@ public class AudioStreamsHelper { private final @Nullable LocalBluetoothManager mBluetoothManager; 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) { mBluetoothManager = bluetoothManager; Loading Loading @@ -144,6 +151,19 @@ public class AudioStreamsHelper { .toList(); } /** 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. */ @VisibleForTesting @Nullable Loading @@ -153,7 +173,18 @@ public class AudioStreamsHelper { /** Checks the connectivity status based on the provided broadcast receive state. */ public static boolean isConnected(BluetoothLeBroadcastReceiveState state) { return state.getBisSyncState().stream().anyMatch(bitmap -> bitmap != 0); 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) { Loading Loading @@ -242,7 +273,8 @@ public class AudioStreamsHelper { List<BluetoothLeBroadcastReceiveState> sourceList = assistant.getAllSources(cachedDevice.getDevice()); if (!sourceList.isEmpty() && sourceList.stream().anyMatch(AudioStreamsHelper::isConnected)) { && (audioSharingHysteresisModeFix() || sourceList.stream().anyMatch(AudioStreamsHelper::isConnected))) { Log.d( TAG, "Lead device has connected broadcast source, device = " Loading @@ -253,7 +285,9 @@ public class AudioStreamsHelper { for (CachedBluetoothDevice device : cachedDevice.getMemberDevice()) { List<BluetoothLeBroadcastReceiveState> list = assistant.getAllSources(device.getDevice()); if (!list.isEmpty() && list.stream().anyMatch(AudioStreamsHelper::isConnected)) { if (!list.isEmpty() && (audioSharingHysteresisModeFix() || list.stream().anyMatch(AudioStreamsHelper::isConnected))) { Log.d( TAG, "Member device has connected broadcast source, device = " Loading Loading
res/values/strings.xml +2 −0 Original line number Diff line number Diff line Loading @@ -13579,6 +13579,8 @@ <string name="audio_streams_dialog_cannot_play">Can\u0027t play this audio stream on <xliff:g example="LE headset" id="device_name">%1$s</xliff:g>.</string> <!-- The preference summary when add source succeed [CHAR LIMIT=NONE] --> <string name="audio_streams_listening_now">Listening now</string> <!-- The preference summary when source is present on sinks [CHAR LIMIT=NONE] --> <string name="audio_streams_present_now">Paused by host</string> <!-- Le audio streams service notification leave broadcast text [CHAR LIMIT=NONE] --> <string name="audio_streams_media_service_notification_leave_broadcast_text">Stop listening</string> <!-- Le audio streams no le device dialog title [CHAR LIMIT=NONE] -->
src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamButtonController.java +20 −6 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.settings.connecteddevice.audiosharing.audiostreams; import static com.android.settingslib.flags.Flags.audioSharingHysteresisModeFix; import android.app.settings.SettingsEnums; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothLeBroadcastAssistant; Loading @@ -41,6 +43,7 @@ import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.utils.ThreadUtils; import com.android.settingslib.widget.ActionButtonsPreference; import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.Executors; Loading Loading @@ -73,14 +76,20 @@ public class AudioStreamButtonController extends BasePreferenceController int sourceId, BluetoothLeBroadcastReceiveState state) { super.onReceiveStateChanged(sink, sourceId, state); if (AudioStreamsHelper.isConnected(state)) { boolean shouldUpdateButton = audioSharingHysteresisModeFix() ? AudioStreamsHelper.hasSourcePresent(state) : AudioStreamsHelper.isConnected(state); if (shouldUpdateButton) { updateButton(); if (AudioStreamsHelper.isConnected(state)) { mMetricsFeatureProvider.action( mContext, SettingsEnums.ACTION_AUDIO_STREAM_JOIN_SUCCEED, SOURCE_ORIGIN_REPOSITORY); } } } @Override public void onSourceAddFailed( Loading Loading @@ -146,8 +155,13 @@ public class AudioStreamButtonController extends BasePreferenceController Log.w(TAG, "updateButton(): preference is null!"); return; } List<BluetoothLeBroadcastReceiveState> sources = audioSharingHysteresisModeFix() ? mAudioStreamsHelper.getAllPresentSources() : mAudioStreamsHelper.getAllConnectedSources(); boolean isConnected = mAudioStreamsHelper.getAllConnectedSources().stream() sources.stream() .map(BluetoothLeBroadcastReceiveState::getBroadcastId) .anyMatch(connectedBroadcastId -> connectedBroadcastId == mBroadcastId); Loading
src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamHeaderController.java +34 −4 Original line number Diff line number Diff line Loading @@ -16,6 +16,10 @@ package com.android.settings.connecteddevice.audiosharing.audiostreams; import static com.android.settingslib.flags.Flags.audioSharingHysteresisModeFix; import static java.util.stream.Collectors.toList; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothLeBroadcastAssistant; import android.bluetooth.BluetoothLeBroadcastReceiveState; Loading Loading @@ -48,6 +52,8 @@ public class AudioStreamHeaderController extends BasePreferenceController static final int AUDIO_STREAM_HEADER_LISTENING_NOW_SUMMARY = R.string.audio_streams_listening_now; static final int AUDIO_STREAM_HEADER_PRESENT_NOW_SUMMARY = R.string.audio_streams_present_now; @VisibleForTesting static final String AUDIO_STREAM_HEADER_NOT_LISTENING_SUMMARY = ""; private static final String TAG = "AudioStreamHeaderController"; private static final String KEY = "audio_stream_header"; Loading Loading @@ -80,6 +86,10 @@ public class AudioStreamHeaderController extends BasePreferenceController updateSummary(); mAudioStreamsHelper.startMediaService( mContext, mBroadcastId, mBroadcastName); } else if (audioSharingHysteresisModeFix() && AudioStreamsHelper.hasSourcePresent(state)) { // if source present but not connected, only update the summary updateSummary(); } } }; Loading Loading @@ -140,8 +150,27 @@ public class AudioStreamHeaderController extends BasePreferenceController var unused = ThreadUtils.postOnBackgroundThread( () -> { var connectedSourceList = mAudioStreamsHelper.getAllPresentSources().stream() .filter( state -> (state.getBroadcastId() == mBroadcastId)) .collect(toList()); var latestSummary = mAudioStreamsHelper.getAllConnectedSources().stream() 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) Loading @@ -152,6 +181,7 @@ public class AudioStreamHeaderController extends BasePreferenceController ? mContext.getString( AUDIO_STREAM_HEADER_LISTENING_NOW_SUMMARY) : AUDIO_STREAM_HEADER_NOT_LISTENING_SUMMARY; ThreadUtils.postOnMainThread( () -> { if (mHeaderController != null) { Loading
src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamStateHandler.java +8 −2 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ package com.android.settings.connecteddevice.audiosharing.audiostreams; import static android.text.Spanned.SPAN_EXCLUSIVE_INCLUSIVE; import static com.android.settingslib.flags.Flags.audioSharingHysteresisModeFix; import android.os.Handler; import android.os.Looper; import android.text.SpannableString; Loading Loading @@ -94,8 +96,12 @@ class AudioStreamStateHandler { } preference.setIsConnected( newState == AudioStreamsProgressCategoryController.AudioStreamState .SOURCE_ADDED); == AudioStreamsProgressCategoryController .AudioStreamState.SOURCE_ADDED || (audioSharingHysteresisModeFix() && newState == AudioStreamsProgressCategoryController .AudioStreamState.SOURCE_PRESENT)); preference.setOnPreferenceClickListener(getOnClickListener(controller)); }); } Loading
src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsHelper.java +37 −3 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ 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_TITLE; import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamMediaService.DEVICES; import static com.android.settingslib.flags.Flags.audioSharingHysteresisModeFix; import static java.util.Collections.emptyList; Loading Loading @@ -63,6 +64,12 @@ public class AudioStreamsHelper { private final @Nullable LocalBluetoothManager mBluetoothManager; 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) { mBluetoothManager = bluetoothManager; Loading Loading @@ -144,6 +151,19 @@ public class AudioStreamsHelper { .toList(); } /** 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. */ @VisibleForTesting @Nullable Loading @@ -153,7 +173,18 @@ public class AudioStreamsHelper { /** Checks the connectivity status based on the provided broadcast receive state. */ public static boolean isConnected(BluetoothLeBroadcastReceiveState state) { return state.getBisSyncState().stream().anyMatch(bitmap -> bitmap != 0); 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) { Loading Loading @@ -242,7 +273,8 @@ public class AudioStreamsHelper { List<BluetoothLeBroadcastReceiveState> sourceList = assistant.getAllSources(cachedDevice.getDevice()); if (!sourceList.isEmpty() && sourceList.stream().anyMatch(AudioStreamsHelper::isConnected)) { && (audioSharingHysteresisModeFix() || sourceList.stream().anyMatch(AudioStreamsHelper::isConnected))) { Log.d( TAG, "Lead device has connected broadcast source, device = " Loading @@ -253,7 +285,9 @@ public class AudioStreamsHelper { for (CachedBluetoothDevice device : cachedDevice.getMemberDevice()) { List<BluetoothLeBroadcastReceiveState> list = assistant.getAllSources(device.getDevice()); if (!list.isEmpty() && list.stream().anyMatch(AudioStreamsHelper::isConnected)) { if (!list.isEmpty() && (audioSharingHysteresisModeFix() || list.stream().anyMatch(AudioStreamsHelper::isConnected))) { Log.d( TAG, "Member device has connected broadcast source, device = " Loading