1 /* <lambda>null2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settingslib.volume.domain.interactor 18 19 import android.media.AudioManager 20 import com.android.settingslib.statusbar.notification.domain.interactor.NotificationsSoundPolicyInteractor 21 import com.android.settingslib.volume.data.repository.AudioRepository 22 import com.android.settingslib.volume.shared.model.AudioStream 23 import com.android.settingslib.volume.shared.model.AudioStreamModel 24 import com.android.settingslib.volume.shared.model.RingerMode 25 import kotlinx.coroutines.flow.Flow 26 import kotlinx.coroutines.flow.StateFlow 27 import kotlinx.coroutines.flow.combine 28 import kotlinx.coroutines.flow.first 29 import kotlinx.coroutines.flow.map 30 31 /** Provides audio stream state and an ability to change it */ 32 class AudioVolumeInteractor( 33 private val audioRepository: AudioRepository, 34 private val notificationsSoundPolicyInteractor: NotificationsSoundPolicyInteractor, 35 ) { 36 37 /** State of the [AudioStream]. */ 38 fun getAudioStream(audioStream: AudioStream): Flow<AudioStreamModel> = 39 combine( 40 audioRepository.getAudioStream(audioStream), 41 audioRepository.ringerMode, 42 notificationsSoundPolicyInteractor.isZenMuted(audioStream) 43 ) { streamModel: AudioStreamModel, ringerMode: RingerMode, isZenMuted: Boolean -> 44 streamModel.copy(volume = processVolume(streamModel, ringerMode, isZenMuted)) 45 } 46 47 val ringerMode: StateFlow<RingerMode> 48 get() = audioRepository.ringerMode 49 50 suspend fun setVolume(audioStream: AudioStream, volume: Int) { 51 val streamModel = getAudioStream(audioStream).first() 52 val oldVolume = streamModel.volume 53 if (volume != oldVolume) { 54 audioRepository.setVolume(audioStream, volume) 55 when { 56 volume == streamModel.minVolume -> setMuted(audioStream, true) 57 oldVolume == streamModel.minVolume && volume > streamModel.minVolume -> 58 setMuted(audioStream, false) 59 } 60 } 61 } 62 63 suspend fun setMuted(audioStream: AudioStream, isMuted: Boolean) { 64 val streamModel = getAudioStream(audioStream).first() 65 if (!streamModel.isAffectedByMute) { 66 return 67 } 68 if (audioStream.value == AudioManager.STREAM_RING) { 69 val mode = 70 if (isMuted) AudioManager.RINGER_MODE_VIBRATE else AudioManager.RINGER_MODE_NORMAL 71 audioRepository.setRingerMode(audioStream, RingerMode(mode)) 72 } 73 val mutedChanged = audioRepository.setMuted(audioStream, isMuted) 74 if (mutedChanged && !isMuted) { 75 with(getAudioStream(audioStream).first()) { 76 if (volume == minVolume) { 77 // Slightly increase volume when user un-mutes the stream that is lowered 78 // down to its minimum 79 setVolume(audioStream, volume + 1) 80 } 81 } 82 } 83 } 84 85 /** Checks if the volume can be changed via the UI. */ 86 fun canChangeVolume(audioStream: AudioStream): Flow<Boolean> { 87 return if (audioStream.value == AudioManager.STREAM_NOTIFICATION) { 88 combine( 89 notificationsSoundPolicyInteractor.isZenMuted(audioStream), 90 getAudioStream(AudioStream(AudioManager.STREAM_RING)).map { it.isMuted }, 91 ) { isZenMuted, isRingMuted -> 92 !isZenMuted && !isRingMuted 93 } 94 } else { 95 notificationsSoundPolicyInteractor.isZenMuted(audioStream).map { !it } 96 } 97 } 98 99 private suspend fun processVolume( 100 audioStreamModel: AudioStreamModel, 101 ringerMode: RingerMode, 102 isZenMuted: Boolean, 103 ): Int { 104 if (isZenMuted) { 105 return audioRepository.getLastAudibleVolume(audioStreamModel.audioStream) 106 } 107 val isNotificationOrRing = 108 audioStreamModel.audioStream.value == AudioManager.STREAM_RING || 109 audioStreamModel.audioStream.value == AudioManager.STREAM_NOTIFICATION 110 if (isNotificationOrRing && ringerMode.value == AudioManager.RINGER_MODE_VIBRATE) { 111 // For ringer-mode affected streams, show volume as zero when ringer mode is vibrate 112 if ( 113 audioStreamModel.audioStream.value == AudioManager.STREAM_RING || 114 (audioStreamModel.audioStream.value == AudioManager.STREAM_NOTIFICATION && 115 audioStreamModel.isMuted) 116 ) { 117 return audioStreamModel.minVolume 118 } 119 } else if (audioStreamModel.isMuted) { 120 return audioStreamModel.minVolume 121 } 122 return audioStreamModel.volume 123 } 124 } 125