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

Commit b51480a5 authored by chelseahao's avatar chelseahao
Browse files

Implement onclick behavior for audio sharing dialog buttons.

Test: atest
Bug: 360759048
Flag: com.android.settingslib.flags.audio_sharing_qs_dialog_improvement
Change-Id: I3449499acd746e10f0c1c09ea45616735838e8b0
parent 1d07441d
Loading
Loading
Loading
Loading
+8 −5
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ class AudioSharingButtonViewModel
@AssistedInject
constructor(
    private val localBluetoothManager: LocalBluetoothManager?,
    private val audioSharingInteractor: AudioSharingInteractor,
    private val bluetoothStateInteractor: BluetoothStateInteractor,
    private val deviceItemInteractor: DeviceItemInteractor,
) : ExclusiveActivatable() {
@@ -53,9 +54,10 @@ constructor(
    override suspend fun onActivated(): Nothing {
        combine(
                bluetoothStateInteractor.bluetoothStateUpdate,
                deviceItemInteractor.deviceItemUpdate
            ) { bluetoothState, deviceItem ->
                getButtonState(bluetoothState, deviceItem)
                deviceItemInteractor.deviceItemUpdate,
                audioSharingInteractor.isAudioSharingOn
            ) { bluetoothState, deviceItem, audioSharingOn ->
                getButtonState(bluetoothState, deviceItem, audioSharingOn)
            }
            .collect { mutableButtonState.value = it }
        awaitCancellation()
@@ -63,13 +65,14 @@ constructor(

    private fun getButtonState(
        bluetoothState: Boolean,
        deviceItem: List<DeviceItem>
        deviceItem: List<DeviceItem>,
        audioSharingOn: Boolean
    ): AudioSharingButtonState {
        return when {
            // Don't show button when bluetooth is off
            !bluetoothState -> AudioSharingButtonState.Gone
            // Show sharing audio when broadcasting
            BluetoothUtils.isBroadcasting(localBluetoothManager) ->
            audioSharingOn ->
                AudioSharingButtonState.Visible(
                    R.string.quick_settings_bluetooth_audio_sharing_button_sharing,
                    isActive = true
+21 −1
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.systemui.bluetooth.qsdialog
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import com.android.internal.logging.UiEventLogger
import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.res.R
@@ -36,6 +37,7 @@ constructor(
    @Application private val coroutineScope: CoroutineScope,
    private val viewModelFactory: AudioSharingDialogViewModel.Factory,
    private val sysuiDialogFactory: SystemUIDialog.Factory,
    private val uiEventLogger: UiEventLogger,
) : SystemUIDialog.Delegate {

    override fun createDialog(): SystemUIDialog = sysuiDialogFactory.create(this)
@@ -44,15 +46,33 @@ constructor(
        with(dialog.layoutInflater.inflate(R.layout.audio_sharing_dialog, null)) {
            dialog.setView(this)
            val subtitleTextView = requireViewById<TextView>(R.id.subtitle)
            val shareAudioButton = requireViewById<TextView>(R.id.share_audio_button)
            val switchActiveButton = requireViewById<Button>(R.id.switch_active_button)
            val job =
                coroutineScope.launch {
                    viewModelFactory.create(cachedBluetoothDevice).dialogState.collect {
                    val viewModel = viewModelFactory.create(cachedBluetoothDevice, this)
                    viewModel.dialogState.collect {
                        when (it) {
                            is AudioSharingDialogState.Hide -> dialog.dismiss()
                            is AudioSharingDialogState.Show -> {
                                subtitleTextView.text = it.subtitle
                                switchActiveButton.text = it.switchButtonText
                                switchActiveButton.setOnClickListener {
                                    viewModel.switchActiveClicked()
                                    uiEventLogger.log(
                                        BluetoothTileDialogUiEvent
                                            .AUDIO_SHARING_DIALOG_SWITCH_ACTIVE_CLICKED
                                    )
                                    dialog.dismiss()
                                }
                                shareAudioButton.setOnClickListener {
                                    viewModel.shareAudioClicked()
                                    uiEventLogger.log(
                                        BluetoothTileDialogUiEvent
                                            .AUDIO_SHARING_DIALOG_SHARE_AUDIO_CLICKED
                                    )
                                    dialog.dismiss()
                                }
                            }
                        }
                    }
+13 −1
Original line number Diff line number Diff line
@@ -25,11 +25,13 @@ import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch

sealed class AudioSharingDialogState {
    data object Hide : AudioSharingDialogState()
@@ -41,10 +43,11 @@ class AudioSharingDialogViewModel
@AssistedInject
constructor(
    deviceItemInteractor: DeviceItemInteractor,
    audioSharingInteractor: AudioSharingInteractor,
    private val audioSharingInteractor: AudioSharingInteractor,
    private val context: Context,
    private val localBluetoothManager: LocalBluetoothManager?,
    @Assisted private val cachedBluetoothDevice: CachedBluetoothDevice,
    @Assisted private val coroutineScope: CoroutineScope,
    @Background private val backgroundDispatcher: CoroutineDispatcher,
) {
    val dialogState: Flow<AudioSharingDialogState> =
@@ -64,6 +67,14 @@ constructor(
            .flowOn(backgroundDispatcher)
            .distinctUntilChanged()

    fun switchActiveClicked() {
        coroutineScope.launch { audioSharingInteractor.switchActive(cachedBluetoothDevice) }
    }

    fun shareAudioClicked() {
        coroutineScope.launch { audioSharingInteractor.startAudioSharing() }
    }

    private fun createShowState(
        cachedBluetoothDevice: CachedBluetoothDevice
    ): AudioSharingDialogState {
@@ -92,6 +103,7 @@ constructor(
    interface Factory {
        fun create(
            cachedBluetoothDevice: CachedBluetoothDevice,
            coroutineScope: CoroutineScope
        ): AudioSharingDialogViewModel
    }
}
+27 −0
Original line number Diff line number Diff line
@@ -19,17 +19,26 @@ package com.android.systemui.bluetooth.qsdialog
import com.android.settingslib.bluetooth.BluetoothUtils
import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.settingslib.bluetooth.LocalBluetoothManager
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.flow.Flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.withContext

/** Holds business logic for the audio sharing state. */
interface AudioSharingInteractor {
    val isAudioSharingOn: Flow<Boolean>

    suspend fun isAvailableAudioSharingMediaBluetoothDevice(
        cachedBluetoothDevice: CachedBluetoothDevice
    ): Boolean

    suspend fun switchActive(cachedBluetoothDevice: CachedBluetoothDevice)

    suspend fun startAudioSharing()
}

@SysUISingleton
@@ -37,9 +46,13 @@ 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 suspend fun isAvailableAudioSharingMediaBluetoothDevice(
        cachedBluetoothDevice: CachedBluetoothDevice
    ): Boolean {
@@ -50,11 +63,25 @@ constructor(
            )
        }
    }

    override suspend fun switchActive(cachedBluetoothDevice: CachedBluetoothDevice) {
        audioSharingRepository.setActive(cachedBluetoothDevice)
    }

    override suspend fun startAudioSharing() {
        audioSharingRepository.startAudioSharing()
    }
}

@SysUISingleton
class AudioSharingInteractorEmptyImpl @Inject constructor() : AudioSharingInteractor {
    override val isAudioSharingOn: Flow<Boolean> = flowOf(false)

    override suspend fun isAvailableAudioSharingMediaBluetoothDevice(
        cachedBluetoothDevice: CachedBluetoothDevice
    ) = false

    override suspend fun switchActive(cachedBluetoothDevice: CachedBluetoothDevice) {}

    override suspend fun startAudioSharing() {}
}
+58 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.bluetooth.qsdialog

import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast
import com.android.settingslib.bluetooth.LocalBluetoothManager
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext

interface AudioSharingRepository {

    suspend fun setActive(cachedBluetoothDevice: CachedBluetoothDevice)

    suspend fun startAudioSharing()
}

@SysUISingleton
class AudioSharingRepositoryImpl(
    private val localBluetoothManager: LocalBluetoothManager,
    @Background private val backgroundDispatcher: CoroutineDispatcher,
) : AudioSharingRepository {

    private val leAudioBroadcastProfile: LocalBluetoothLeBroadcast?
        get() = localBluetoothManager.profileManager?.leAudioBroadcastProfile

    override suspend fun setActive(cachedBluetoothDevice: CachedBluetoothDevice) {
        withContext(backgroundDispatcher) { cachedBluetoothDevice.setActive() }
    }

    override suspend fun startAudioSharing() {
        withContext(backgroundDispatcher) { leAudioBroadcastProfile?.startPrivateBroadcast() }
    }
}

@SysUISingleton
class AudioSharingRepositoryEmptyImpl : AudioSharingRepository {

    override suspend fun setActive(cachedBluetoothDevice: CachedBluetoothDevice) {}

    override suspend fun startAudioSharing() {}
}
Loading