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

Commit c53b10fc authored by Anton Potapov's avatar Anton Potapov
Browse files

Change audio stream when calling with BLE headset

Flag: aconfig new_volume_panel TRUNKFOOD
Test: manual on the phone with a compatible headset
Bug: 330107223
Change-Id: If6ea943349de9c52012824c78cae3279ee01cc3c
parent 020580d7
Loading
Loading
Loading
Loading
+85 −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.volume.panel.component.volume.domain.interactor

import android.media.AudioDeviceInfo
import android.media.AudioManager
import com.android.settingslib.volume.data.repository.AudioRepository
import com.android.settingslib.volume.shared.model.AudioStream
import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputInteractor
import com.android.systemui.volume.panel.component.mediaoutput.shared.model.MediaDeviceSession
import com.android.systemui.volume.panel.component.mediaoutput.shared.model.isTheSameSession
import com.android.systemui.volume.panel.component.volume.domain.model.SliderType
import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combineTransform
import kotlinx.coroutines.flow.stateIn

/** Provides volume sliders to show in the Volume Panel. */
@VolumePanelScope
class AudioSlidersInteractor
@Inject
constructor(
    @VolumePanelScope scope: CoroutineScope,
    mediaOutputInteractor: MediaOutputInteractor,
    audioRepository: AudioRepository,
) {

    val volumePanelSliders: StateFlow<List<SliderType>> =
        combineTransform(
                mediaOutputInteractor.activeMediaDeviceSessions,
                mediaOutputInteractor.defaultActiveMediaSession,
                audioRepository.communicationDevice,
            ) { activeSessions, defaultSession, communicationDevice ->
                coroutineScope {
                    val viewModels = buildList {
                        if (defaultSession?.isTheSameSession(activeSessions.remote) == true) {
                            addSession(activeSessions.remote)
                            addStream(AudioManager.STREAM_MUSIC)
                        } else {
                            addStream(AudioManager.STREAM_MUSIC)
                            addSession(activeSessions.remote)
                        }

                        if (communicationDevice?.type == AudioDeviceInfo.TYPE_BLUETOOTH_SCO) {
                            addStream(AudioManager.STREAM_BLUETOOTH_SCO)
                        } else {
                            addStream(AudioManager.STREAM_VOICE_CALL)
                        }
                        addStream(AudioManager.STREAM_RING)
                        addStream(AudioManager.STREAM_NOTIFICATION)
                        addStream(AudioManager.STREAM_ALARM)
                    }
                    emit(viewModels)
                }
            }
            .stateIn(scope, SharingStarted.Eagerly, emptyList())

    private fun MutableList<SliderType>.addSession(remoteMediaDeviceSession: MediaDeviceSession?) {
        if (remoteMediaDeviceSession?.canAdjustVolume == true) {
            add(SliderType.MediaDeviceCast(remoteMediaDeviceSession))
        }
    }

    private fun MutableList<SliderType>.addStream(stream: Int) {
        add(SliderType.Stream(AudioStream(stream)))
    }
}
+2 −1
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.systemui.volume.panel.component.volume.domain.model

import com.android.settingslib.volume.shared.model.AudioStream
import com.android.systemui.volume.panel.component.mediaoutput.shared.model.MediaDeviceSession

/** The type of volume slider that can be shown at the UI. */
sealed interface SliderType {
@@ -25,5 +26,5 @@ sealed interface SliderType {
    data class Stream(val stream: AudioStream) : SliderType

    /** The represents media device casting volume. */
    data object MediaDeviceCast : SliderType
    data class MediaDeviceCast(val session: MediaDeviceSession) : SliderType
}
+4 −0
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ constructor(
        mapOf(
            AudioStream(AudioManager.STREAM_MUSIC) to R.drawable.ic_music_note,
            AudioStream(AudioManager.STREAM_VOICE_CALL) to R.drawable.ic_call,
            AudioStream(AudioManager.STREAM_BLUETOOTH_SCO) to R.drawable.ic_call,
            AudioStream(AudioManager.STREAM_RING) to R.drawable.ic_ring_volume,
            AudioStream(AudioManager.STREAM_NOTIFICATION) to R.drawable.ic_volume_ringer,
            AudioStream(AudioManager.STREAM_ALARM) to R.drawable.ic_volume_alarm,
@@ -61,6 +62,7 @@ constructor(
        mapOf(
            AudioStream(AudioManager.STREAM_MUSIC) to R.string.stream_music,
            AudioStream(AudioManager.STREAM_VOICE_CALL) to R.string.stream_voice_call,
            AudioStream(AudioManager.STREAM_BLUETOOTH_SCO) to R.string.stream_voice_call,
            AudioStream(AudioManager.STREAM_RING) to R.string.stream_ring,
            AudioStream(AudioManager.STREAM_NOTIFICATION) to R.string.stream_notification,
            AudioStream(AudioManager.STREAM_ALARM) to R.string.stream_alarm,
@@ -78,6 +80,8 @@ constructor(
                VolumePanelUiEvent.VOLUME_PANEL_MUSIC_SLIDER_TOUCHED,
            AudioStream(AudioManager.STREAM_VOICE_CALL) to
                VolumePanelUiEvent.VOLUME_PANEL_VOICE_CALL_SLIDER_TOUCHED,
            AudioStream(AudioManager.STREAM_BLUETOOTH_SCO) to
                VolumePanelUiEvent.VOLUME_PANEL_VOICE_CALL_SLIDER_TOUCHED,
            AudioStream(AudioManager.STREAM_RING) to
                VolumePanelUiEvent.VOLUME_PANEL_RING_SLIDER_TOUCHED,
            AudioStream(AudioManager.STREAM_NOTIFICATION) to
+24 −42
Original line number Diff line number Diff line
@@ -16,12 +16,12 @@

package com.android.systemui.volume.panel.component.volume.ui.viewmodel

import android.media.AudioManager
import com.android.settingslib.volume.shared.model.AudioStream
import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaDeviceSessionInteractor
import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputInteractor
import com.android.systemui.volume.panel.component.mediaoutput.shared.model.MediaDeviceSession
import com.android.systemui.volume.panel.component.mediaoutput.shared.model.isTheSameSession
import com.android.systemui.volume.panel.component.volume.domain.interactor.AudioSlidersInteractor
import com.android.systemui.volume.panel.component.volume.domain.model.SliderType
import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.AudioStreamSliderViewModel
import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.CastVolumeSliderViewModel
import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.SliderViewModel
@@ -33,12 +33,12 @@ import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combineTransform
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.transformLatest
import kotlinx.coroutines.launch

/**
@@ -55,27 +55,20 @@ constructor(
    private val mediaDeviceSessionInteractor: MediaDeviceSessionInteractor,
    private val streamSliderViewModelFactory: AudioStreamSliderViewModel.Factory,
    private val castVolumeSliderViewModelFactory: CastVolumeSliderViewModel.Factory,
    streamsInteractor: AudioSlidersInteractor,
) {

    val sliderViewModels: StateFlow<List<SliderViewModel>> =
        combineTransform(
                mediaOutputInteractor.activeMediaDeviceSessions,
                mediaOutputInteractor.defaultActiveMediaSession,
            ) { activeSessions, defaultSession ->
        streamsInteractor.volumePanelSliders
            .transformLatest { sliderTypes ->
                coroutineScope {
                    val viewModels = buildList {
                        if (defaultSession?.isTheSameSession(activeSessions.remote) == true) {
                            addRemoteViewModelIfNeeded(this, activeSessions.remote)
                            addStreamViewModel(this, AudioManager.STREAM_MUSIC)
                        } else {
                            addStreamViewModel(this, AudioManager.STREAM_MUSIC)
                            addRemoteViewModelIfNeeded(this, activeSessions.remote)
                    val viewModels =
                        sliderTypes.map { type ->
                            when (type) {
                                is SliderType.Stream -> createStreamViewModel(type.stream)
                                is SliderType.MediaDeviceCast ->
                                    createSessionViewModel(type.session)
                            }

                        addStreamViewModel(this, AudioManager.STREAM_VOICE_CALL)
                        addStreamViewModel(this, AudioManager.STREAM_RING)
                        addStreamViewModel(this, AudioManager.STREAM_NOTIFICATION)
                        addStreamViewModel(this, AudioManager.STREAM_ALARM)
                        }
                    emit(viewModels)
                }
@@ -98,29 +91,18 @@ constructor(
        scope.launch { mutableIsExpanded.emit(isExpanded) }
    }

    private fun CoroutineScope.addRemoteViewModelIfNeeded(
        list: MutableList<SliderViewModel>,
        remoteMediaDeviceSession: MediaDeviceSession?
    ) {
        if (remoteMediaDeviceSession?.canAdjustVolume == true) {
            val viewModel =
                castVolumeSliderViewModelFactory.create(
                    remoteMediaDeviceSession,
                    this,
                )
            list.add(viewModel)
        }
    private fun CoroutineScope.createSessionViewModel(
        session: MediaDeviceSession
    ): CastVolumeSliderViewModel {
        return castVolumeSliderViewModelFactory.create(session, this)
    }

    private fun CoroutineScope.addStreamViewModel(
        list: MutableList<SliderViewModel>,
        stream: Int,
    ) {
        val viewModel =
            streamSliderViewModelFactory.create(
                AudioStreamSliderViewModel.FactoryAudioStreamWrapper(AudioStream(stream)),
    private fun CoroutineScope.createStreamViewModel(
        stream: AudioStream,
    ): AudioStreamSliderViewModel {
        return streamSliderViewModelFactory.create(
            AudioStreamSliderViewModel.FactoryAudioStreamWrapper(stream),
            this,
        )
        list.add(viewModel)
    }
}