Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c8821821 authored by chelseahao's avatar chelseahao
Browse files

Move `BluetoothUtils.isAudioSharingEnabled` away from `AudioSharingModule` as...

Move `BluetoothUtils.isAudioSharingEnabled` away from `AudioSharingModule` as it contains binder call.

Also use `isAudioSharingEnabled` from `AudioSharingRepository` throughout the code for better centralization.

Test: atest
Bug: 360759048
Flag: com.android.settingslib.flags.audio_sharing_qs_dialog_improvement
Change-Id: I885485a5a696eefa73598d3ad1cd6c192daf796f
parent 89eaf2bd
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -74,6 +74,8 @@ interface AudioSharingRepository {
    /** The headset groupId to volume map during audio sharing. */
    val volumeMap: StateFlow<GroupIdToVolumes>

    suspend fun audioSharingAvailable(): Boolean

    /** Set the volume of secondary headset during audio sharing. */
    suspend fun setSecondaryVolume(
        @IntRange(from = AUDIO_SHARING_VOLUME_MIN.toLong(), to = AUDIO_SHARING_VOLUME_MAX.toLong())
@@ -216,6 +218,12 @@ class AudioSharingRepositoryImpl(
        }
            .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), emptyMap())

    override suspend fun audioSharingAvailable(): Boolean {
        return withContext(backgroundCoroutineContext) {
            BluetoothUtils.isAudioSharingEnabled()
        }
    }

    override suspend fun setSecondaryVolume(
        @IntRange(from = AUDIO_SHARING_VOLUME_MIN.toLong(), to = AUDIO_SHARING_VOLUME_MAX.toLong())
        volume: Int
@@ -262,6 +270,8 @@ class AudioSharingRepositoryEmptyImpl : AudioSharingRepository {
        MutableStateFlow(BluetoothCsipSetCoordinator.GROUP_ID_INVALID)
    override val volumeMap: StateFlow<GroupIdToVolumes> = MutableStateFlow(emptyMap())

    override suspend fun audioSharingAvailable(): Boolean = false

    override suspend fun setSecondaryVolume(
        @IntRange(from = AUDIO_SHARING_VOLUME_MIN.toLong(), to = AUDIO_SHARING_VOLUME_MAX.toLong())
        volume: Int
+9 −5
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ class AudioSharingDeviceItemActionInteractorImpl
@Inject
constructor(
    private val activityStarter: ActivityStarter,
    private val audioSharingInteractor: AudioSharingInteractor,
    private val dialogTransitionAnimator: DialogTransitionAnimator,
    private val localBluetoothManager: LocalBluetoothManager?,
    @Main private val mainDispatcher: CoroutineDispatcher,
@@ -55,6 +56,9 @@ constructor(

    override suspend fun onClick(deviceItem: DeviceItem, dialog: SystemUIDialog) {
        withContext(backgroundDispatcher) {
            if (!audioSharingInteractor.audioSharingAvailable()) {
                return@withContext deviceItemActionInteractorImpl.onClick(deviceItem, dialog)
            }
            val inAudioSharing = BluetoothUtils.isBroadcasting(localBluetoothManager)
            logger.logDeviceClickInAudioSharingWhenEnabled(inAudioSharing)

@@ -72,7 +76,7 @@ constructor(
                        launchSettings(deviceItem.cachedBluetoothDevice.device, dialog)
                        logger.logLaunchSettingsCriteriaMatched(
                            "AvailableAudioSharingDeviceClicked",
                            deviceItem
                            deviceItem,
                        )
                    }
                    uiEventLogger.log(
@@ -99,13 +103,13 @@ constructor(

    private fun inSharingAndDeviceNoSource(
        inAudioSharing: Boolean,
        deviceItem: DeviceItem
        deviceItem: DeviceItem,
    ): Boolean {
        return inAudioSharing &&
            deviceItem.isMediaDevice &&
            !BluetoothUtils.hasConnectedBroadcastSource(
                deviceItem.cachedBluetoothDevice,
                localBluetoothManager
                localBluetoothManager,
            )
    }

@@ -116,14 +120,14 @@ constructor(
                    EXTRA_SHOW_FRAGMENT_ARGUMENTS,
                    Bundle().apply {
                        putParcelable(LocalBluetoothLeBroadcast.EXTRA_BLUETOOTH_DEVICE, device)
                    }
                    },
                )
            }
        intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK
        activityStarter.postStartActivityDismissingKeyguard(
            intent,
            0,
            dialogTransitionAnimator.createActivityTransitionController(dialog)
            dialogTransitionAnimator.createActivityTransitionController(dialog),
        )
    }

+64 −20
Original line number Diff line number Diff line
@@ -20,15 +20,18 @@ import com.android.settingslib.bluetooth.BluetoothUtils
import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.settingslib.bluetooth.LocalBluetoothManager
import com.android.settingslib.bluetooth.onPlaybackStarted
import com.android.settingslib.volume.data.repository.AudioSharingRepository as SettingsLibAudioSharingRepository
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.withContext

@@ -47,58 +50,97 @@ interface AudioSharingInteractor {
    suspend fun switchActive(cachedBluetoothDevice: CachedBluetoothDevice)

    suspend fun startAudioSharing()

    suspend fun audioSharingAvailable(): Boolean
}

@SysUISingleton
@OptIn(ExperimentalCoroutinesApi::class)
class AudioSharingInteractorImpl
@Inject
constructor(
    private val localBluetoothManager: LocalBluetoothManager?,
    private val audioSharingRepository: AudioSharingRepository,
    settingsLibAudioSharingRepository: SettingsLibAudioSharingRepository,
    @Background private val backgroundDispatcher: CoroutineDispatcher,
) : AudioSharingInteractor {

    override val isAudioSharingOn = settingsLibAudioSharingRepository.inAudioSharing
    override val isAudioSharingOn: Flow<Boolean> =
        flow { emit(audioSharingAvailable()) }
            .flatMapLatest { isEnabled ->
                if (isEnabled) {
                    audioSharingRepository.inAudioSharing
                } else {
                    flowOf(false)
                }
            }
            .flowOn(backgroundDispatcher)

    override val audioSourceStateUpdate = audioSharingRepository.audioSourceStateUpdate
    override val audioSourceStateUpdate =
        isAudioSharingOn
            .flatMapLatest {
                if (it) {
                    audioSharingRepository.audioSourceStateUpdate
                } else {
                    emptyFlow()
                }
            }
            .flowOn(backgroundDispatcher)

    override suspend fun handleAudioSourceWhenReady() {
        withContext(backgroundDispatcher) {
            if (audioSharingAvailable()) {
                audioSharingRepository.leAudioBroadcastProfile?.let { profile ->
                    isAudioSharingOn
                        .mapNotNull { audioSharingOn ->
                            if (audioSharingOn) {
                            // onPlaybackStarted could emit multiple times during one audio sharing
                            // session, we only perform add source on the first time
                                // onPlaybackStarted could emit multiple times during one
                                // audio sharing session, we only perform add source on the
                                // first time
                                profile.onPlaybackStarted.firstOrNull()
                            } else {
                                null
                            }
                        }
                        .flowOn(backgroundDispatcher)
                        .collect { audioSharingRepository.addSource() }
                }
            }
        }
    }

    override suspend fun isAvailableAudioSharingMediaBluetoothDevice(
        cachedBluetoothDevice: CachedBluetoothDevice
    ): Boolean {
        return withContext(backgroundDispatcher) {
            if (audioSharingAvailable()) {
                BluetoothUtils.isAvailableAudioSharingMediaBluetoothDevice(
                    cachedBluetoothDevice,
                localBluetoothManager
                    localBluetoothManager,
                )
            } else {
                false
            }
        }
    }

    override suspend fun switchActive(cachedBluetoothDevice: CachedBluetoothDevice) {
        if (!audioSharingAvailable()) {
            return
        }
        audioSharingRepository.setActive(cachedBluetoothDevice)
    }

    override suspend fun startAudioSharing() {
        if (!audioSharingAvailable()) {
            return
        }
        audioSharingRepository.startAudioSharing()
    }

    // TODO(b/367965193): Move this after flags rollout
    override suspend fun audioSharingAvailable(): Boolean {
        return audioSharingRepository.audioSharingAvailable()
    }
}

@SysUISingleton
@@ -116,4 +158,6 @@ class AudioSharingInteractorEmptyImpl @Inject constructor() : AudioSharingIntera
    override suspend fun switchActive(cachedBluetoothDevice: CachedBluetoothDevice) {}

    override suspend fun startAudioSharing() {}

    override suspend fun audioSharingAvailable(): Boolean = false
}
+34 −2
Original line number Diff line number Diff line
@@ -21,10 +21,13 @@ import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant
import com.android.settingslib.bluetooth.LocalBluetoothManager
import com.android.settingslib.bluetooth.onSourceConnectedOrRemoved
import com.android.settingslib.volume.data.repository.AudioSharingRepository as SettingsLibAudioSharingRepository
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.withContext

@@ -33,6 +36,10 @@ interface AudioSharingRepository {

    val audioSourceStateUpdate: Flow<Unit>

    val inAudioSharing: StateFlow<Boolean>

    suspend fun audioSharingAvailable(): Boolean

    suspend fun addSource()

    suspend fun setActive(cachedBluetoothDevice: CachedBluetoothDevice)
@@ -43,6 +50,7 @@ interface AudioSharingRepository {
@SysUISingleton
class AudioSharingRepositoryImpl(
    private val localBluetoothManager: LocalBluetoothManager,
    private val settingsLibAudioSharingRepository: SettingsLibAudioSharingRepository,
    @Background private val backgroundDispatcher: CoroutineDispatcher,
) : AudioSharingRepository {

@@ -55,8 +63,18 @@ class AudioSharingRepositoryImpl(
    override val audioSourceStateUpdate: Flow<Unit> =
        leAudioBroadcastAssistantProfile?.onSourceConnectedOrRemoved ?: emptyFlow()

    override val inAudioSharing: StateFlow<Boolean> =
        settingsLibAudioSharingRepository.inAudioSharing

    override suspend fun audioSharingAvailable(): Boolean {
        return settingsLibAudioSharingRepository.audioSharingAvailable()
    }

    override suspend fun addSource() {
        withContext(backgroundDispatcher) {
            if (!settingsLibAudioSharingRepository.audioSharingAvailable()) {
                return@withContext
            }
            leAudioBroadcastProfile?.latestBluetoothLeBroadcastMetadata?.let { metadata ->
                leAudioBroadcastAssistantProfile?.let {
                    it.allConnectedDevices.forEach { sink -> it.addSource(sink, metadata, false) }
@@ -66,11 +84,21 @@ class AudioSharingRepositoryImpl(
    }

    override suspend fun setActive(cachedBluetoothDevice: CachedBluetoothDevice) {
        withContext(backgroundDispatcher) { cachedBluetoothDevice.setActive() }
        withContext(backgroundDispatcher) {
            if (!settingsLibAudioSharingRepository.audioSharingAvailable()) {
                return@withContext
            }
            cachedBluetoothDevice.setActive()
        }
    }

    override suspend fun startAudioSharing() {
        withContext(backgroundDispatcher) { leAudioBroadcastProfile?.startPrivateBroadcast() }
        withContext(backgroundDispatcher) {
            if (!settingsLibAudioSharingRepository.audioSharingAvailable()) {
                return@withContext
            }
            leAudioBroadcastProfile?.startPrivateBroadcast()
        }
    }
}

@@ -80,6 +108,10 @@ class AudioSharingRepositoryEmptyImpl : AudioSharingRepository {

    override val audioSourceStateUpdate: Flow<Unit> = emptyFlow()

    override val inAudioSharing: StateFlow<Boolean> = MutableStateFlow(false)

    override suspend fun audioSharingAvailable(): Boolean = false

    override suspend fun addSource() {}

    override suspend fun setActive(cachedBluetoothDevice: CachedBluetoothDevice) {}
+19 −20
Original line number Diff line number Diff line
@@ -28,7 +28,6 @@ import androidx.annotation.StringRes
import androidx.annotation.VisibleForTesting
import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.logging.UiEventLogger
import com.android.settingslib.bluetooth.BluetoothUtils
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast
import com.android.settingslib.flags.Flags.audioSharingQsDialogImprovement
import com.android.systemui.Prefs
@@ -106,7 +105,7 @@ constructor(
                    expandable?.dialogTransitionController(
                        DialogCuj(
                            InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN,
                            INTERACTION_JANK_TAG
                            INTERACTION_JANK_TAG,
                        )
                    )
                controller?.let {
@@ -121,7 +120,7 @@ constructor(
                // stop the progress bar.
                combine(
                        deviceItemInteractor.deviceItemUpdate,
                        deviceItemInteractor.showSeeAllUpdate
                        deviceItemInteractor.showSeeAllUpdate,
                    ) { deviceItem, showSeeAll ->
                        updateDialogUiJob?.cancel()
                        updateDialogUiJob = launch {
@@ -131,7 +130,7 @@ constructor(
                                    deviceItem,
                                    showSeeAll,
                                    showPairNewDevice =
                                        bluetoothStateInteractor.isBluetoothEnabled()
                                        bluetoothStateInteractor.isBluetoothEnabled(),
                                )
                                animateProgressBar(dialog, false)
                            }
@@ -145,13 +144,13 @@ constructor(
                        deviceItemInteractor.deviceItemUpdateRequest,
                        bluetoothDeviceMetadataInteractor.metadataUpdate,
                        if (
                            BluetoothUtils.isAudioSharingEnabled() &&
                            audioSharingInteractor.audioSharingAvailable() &&
                                audioSharingQsDialogImprovement()
                        ) {
                            audioSharingInteractor.audioSourceStateUpdate
                        } else {
                            emptyFlow()
                        }
                        },
                    )
                    .onEach {
                        dialogDelegate.animateProgressBar(dialog, true)
@@ -159,13 +158,13 @@ constructor(
                        updateDeviceItemJob = launch {
                            deviceItemInteractor.updateDeviceItems(
                                context,
                                DeviceFetchTrigger.BLUETOOTH_CALLBACK_RECEIVED
                                DeviceFetchTrigger.BLUETOOTH_CALLBACK_RECEIVED,
                            )
                        }
                    }
                    .launchIn(this)

                if (BluetoothUtils.isAudioSharingEnabled()) {
                if (audioSharingInteractor.audioSharingAvailable()) {
                    if (audioSharingQsDialogImprovement()) {
                        launch { audioSharingInteractor.handleAudioSourceWhenReady() }
                    }
@@ -179,7 +178,7 @@ constructor(
                                            dialog,
                                            VISIBLE,
                                            context.getString(it.resId),
                                            it.isActive
                                            it.isActive,
                                        )
                                    }
                                    is AudioSharingButtonState.Gone -> {
@@ -187,7 +186,7 @@ constructor(
                                            dialog,
                                            GONE,
                                            label = null,
                                            isActive = false
                                            isActive = false,
                                        )
                                    }
                                }
@@ -204,13 +203,13 @@ constructor(
                        dialogDelegate.onBluetoothStateUpdated(
                            dialog,
                            it,
                            UiProperties.build(it, isAutoOnToggleFeatureAvailable())
                            UiProperties.build(it, isAutoOnToggleFeatureAvailable()),
                        )
                        updateDeviceItemJob?.cancel()
                        updateDeviceItemJob = launch {
                            deviceItemInteractor.updateDeviceItems(
                                context,
                                DeviceFetchTrigger.BLUETOOTH_STATE_CHANGE_RECEIVED
                                DeviceFetchTrigger.BLUETOOTH_STATE_CHANGE_RECEIVED,
                            )
                        }
                    }
@@ -252,7 +251,7 @@ constructor(
                                dialog,
                                it,
                                if (it) R.string.turn_on_bluetooth_auto_info_enabled
                                else R.string.turn_on_bluetooth_auto_info_disabled
                                else R.string.turn_on_bluetooth_auto_info_disabled,
                            )
                        }
                        .launchIn(this)
@@ -274,18 +273,18 @@ constructor(
            withContext(backgroundDispatcher) {
                sharedPreferences.getInt(
                    CONTENT_HEIGHT_PREF_KEY,
                    ViewGroup.LayoutParams.WRAP_CONTENT
                    ViewGroup.LayoutParams.WRAP_CONTENT,
                )
            }

        return bluetoothDialogDelegateFactory.create(
            UiProperties.build(
                bluetoothStateInteractor.isBluetoothEnabled(),
                isAutoOnToggleFeatureAvailable()
                isAutoOnToggleFeatureAvailable(),
            ),
            cachedContentHeight,
            this@BluetoothTileDialogViewModel,
            { cancelJob() }
            { cancelJob() },
        )
    }

@@ -297,7 +296,7 @@ constructor(
                    EXTRA_SHOW_FRAGMENT_ARGUMENTS,
                    Bundle().apply {
                        putString("device_address", deviceItem.cachedBluetoothDevice.address)
                    }
                    },
                )
            }
        startSettingsActivity(intent, view)
@@ -321,7 +320,7 @@ constructor(
                    EXTRA_SHOW_FRAGMENT_ARGUMENTS,
                    Bundle().apply {
                        putBoolean(LocalBluetoothLeBroadcast.EXTRA_START_LE_AUDIO_SHARING, true)
                    }
                    },
                )
            }
        startSettingsActivity(intent, view)
@@ -367,7 +366,7 @@ constructor(
        companion object {
            internal fun build(
                isBluetoothEnabled: Boolean,
                isAutoOnToggleFeatureAvailable: Boolean
                isAutoOnToggleFeatureAvailable: Boolean,
            ) =
                UiProperties(
                    subTitleResId = getSubtitleResId(isBluetoothEnabled),
@@ -377,7 +376,7 @@ constructor(
                    scrollViewMinHeightResId =
                        if (isAutoOnToggleFeatureAvailable)
                            R.dimen.bluetooth_dialog_scroll_view_min_height_with_auto_on
                        else R.dimen.bluetooth_dialog_scroll_view_min_height
                        else R.dimen.bluetooth_dialog_scroll_view_min_height,
                )
        }
    }
Loading