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

Commit d663603b authored by Anton Potapov's avatar Anton Potapov Committed by Android (Google) Code Review
Browse files

Merge "Change audio stream when calling with BLE headset" into main

parents c5a7c5aa c53b10fc
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)
    }
}