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

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

Merge "Observe volume setting alongside broadcast event to faster react to the...

Merge "Observe volume setting alongside broadcast event to faster react to the volume changes" into main
parents 34eb1735 7f75885a
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
@@ -62,16 +63,18 @@ class CaptioningRepositoryImpl(
        captioningChanges
            .filterIsInstance(CaptioningChange.IsSystemAudioCaptioningEnabled::class)
            .map { it.isEnabled }
            .onStart { emit(captioningManager.isSystemAudioCaptioningEnabled) }
            .stateIn(
                coroutineScope,
                SharingStarted.WhileSubscribed(),
                captioningManager.isSystemAudioCaptioningEnabled
                captioningManager.isSystemAudioCaptioningEnabled,
            )

    override val isSystemAudioCaptioningUiEnabled: StateFlow<Boolean> =
        captioningChanges
            .filterIsInstance(CaptioningChange.IsSystemUICaptioningEnabled::class)
            .map { it.isEnabled }
            .onStart { emit(captioningManager.isSystemAudioCaptioningUiEnabled) }
            .stateIn(
                coroutineScope,
                SharingStarted.WhileSubscribed(),
+49 −12
Original line number Diff line number Diff line
@@ -16,9 +16,13 @@

package com.android.settingslib.volume.data.repository

import android.content.ContentResolver
import android.database.ContentObserver
import android.media.AudioDeviceInfo
import android.media.AudioManager
import android.media.AudioManager.OnCommunicationDeviceChangedListener
import android.provider.Settings
import androidx.concurrent.futures.DirectExecutor
import com.android.internal.util.ConcurrentUtils
import com.android.settingslib.volume.shared.AudioManagerEventsReceiver
import com.android.settingslib.volume.shared.model.AudioManagerEvent
@@ -33,12 +37,13 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
@@ -84,17 +89,31 @@ interface AudioRepository {
class AudioRepositoryImpl(
    private val audioManagerEventsReceiver: AudioManagerEventsReceiver,
    private val audioManager: AudioManager,
    private val contentResolver: ContentResolver,
    private val backgroundCoroutineContext: CoroutineContext,
    private val coroutineScope: CoroutineScope,
) : AudioRepository {

    private val streamSettingNames: Map<AudioStream, String> =
        mapOf(
            AudioStream(AudioManager.STREAM_VOICE_CALL) to Settings.System.VOLUME_VOICE,
            AudioStream(AudioManager.STREAM_SYSTEM) to Settings.System.VOLUME_SYSTEM,
            AudioStream(AudioManager.STREAM_RING) to Settings.System.VOLUME_RING,
            AudioStream(AudioManager.STREAM_MUSIC) to Settings.System.VOLUME_MUSIC,
            AudioStream(AudioManager.STREAM_ALARM) to Settings.System.VOLUME_ALARM,
            AudioStream(AudioManager.STREAM_NOTIFICATION) to Settings.System.VOLUME_NOTIFICATION,
            AudioStream(AudioManager.STREAM_BLUETOOTH_SCO) to Settings.System.VOLUME_BLUETOOTH_SCO,
            AudioStream(AudioManager.STREAM_ACCESSIBILITY) to Settings.System.VOLUME_ACCESSIBILITY,
            AudioStream(AudioManager.STREAM_ASSISTANT) to Settings.System.VOLUME_ASSISTANT,
        )

    override val mode: StateFlow<Int> =
        callbackFlow {
                val listener =
                    AudioManager.OnModeChangedListener { newMode -> launch { send(newMode) } }
                val listener = AudioManager.OnModeChangedListener { newMode -> trySend(newMode) }
                audioManager.addOnModeChangedListener(ConcurrentUtils.DIRECT_EXECUTOR, listener)
                awaitClose { audioManager.removeOnModeChangedListener(listener) }
            }
            .onStart { emit(audioManager.mode) }
            .flowOn(backgroundCoroutineContext)
            .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), audioManager.mode)

@@ -102,6 +121,7 @@ class AudioRepositoryImpl(
        audioManagerEventsReceiver.events
            .filterIsInstance(AudioManagerEvent.InternalRingerModeChanged::class)
            .map { RingerMode(audioManager.ringerModeInternal) }
            .onStart { emit(RingerMode(audioManager.ringerModeInternal)) }
            .flowOn(backgroundCoroutineContext)
            .stateIn(
                coroutineScope,
@@ -122,6 +142,7 @@ class AudioRepositoryImpl(
                }
                .filterNotNull()
                .map { audioManager.communicationDevice }
                .onStart { emit(audioManager.communicationDevice) }
                .flowOn(backgroundCoroutineContext)
                .stateIn(
                    coroutineScope,
@@ -130,17 +151,18 @@ class AudioRepositoryImpl(
                )

    override fun getAudioStream(audioStream: AudioStream): Flow<AudioStreamModel> {
        return audioManagerEventsReceiver.events
            .filter {
        return merge(
                audioManagerEventsReceiver.events.filter {
                    if (it is StreamAudioManagerEvent) {
                        it.audioStream == audioStream
                    } else {
                        true
                    }
            }
                },
                volumeSettingChanges(audioStream),
            )
            .map { getCurrentAudioStream(audioStream) }
            .onStart { emit(getCurrentAudioStream(audioStream)) }
            .conflate()
            .flowOn(backgroundCoroutineContext)
    }

@@ -195,4 +217,19 @@ class AudioRepositoryImpl(
            // return STREAM_VOICE_CALL in getAudioStream
            audioManager.getStreamMinVolume(AudioManager.STREAM_VOICE_CALL)
        }

    private fun volumeSettingChanges(audioStream: AudioStream): Flow<Unit> {
        val uri = streamSettingNames[audioStream]?.let(Settings.System::getUriFor)
        uri ?: return emptyFlow()
        return callbackFlow {
            val observer =
                object : ContentObserver(DirectExecutor.INSTANCE, 0) {
                    override fun onChange(selfChange: Boolean) {
                        launch { send(Unit) }
                    }
                }
            contentResolver.registerContentObserver(uri, false, observer)
            awaitClose { contentResolver.unregisterContentObserver(observer) }
        }
    }
}
+13 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.settingslib.volume.data.repository

import android.content.ContentResolver
import android.database.ContentObserver
import android.media.AudioDeviceInfo
import android.media.AudioManager
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -38,6 +40,7 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Captor
import org.mockito.Mock
@@ -55,9 +58,11 @@ class AudioRepositoryTest {
    @Captor
    private lateinit var communicationDeviceListenerCaptor:
        ArgumentCaptor<AudioManager.OnCommunicationDeviceChangedListener>
    @Captor private lateinit var contentObserver: ArgumentCaptor<ContentObserver>

    @Mock private lateinit var audioManager: AudioManager
    @Mock private lateinit var communicationDevice: AudioDeviceInfo
    @Mock private lateinit var contentResolver: ContentResolver

    private val eventsReceiver = FakeAudioManagerEventsReceiver()
    private val volumeByStream: MutableMap<Int, Int> = mutableMapOf()
@@ -80,6 +85,7 @@ class AudioRepositoryTest {
            val streamType = it.arguments[0] as Int
            volumeByStream[it.arguments[0] as Int] = it.arguments[1] as Int
            triggerEvent(AudioManagerEvent.StreamVolumeChanged(AudioStream(streamType)))
            triggerSettingChange()
        }
        `when`(audioManager.adjustStreamVolume(anyInt(), anyInt(), anyInt())).then {
            val streamType = it.arguments[0] as Int
@@ -100,6 +106,7 @@ class AudioRepositoryTest {
            AudioRepositoryImpl(
                eventsReceiver,
                audioManager,
                contentResolver,
                testScope.testScheduler,
                testScope.backgroundScope,
            )
@@ -254,6 +261,12 @@ class AudioRepositoryTest {
        modeListenerCaptor.value.onModeChanged(mode)
    }

    private fun triggerSettingChange(selfChange: Boolean = false) {
        verify(contentResolver)
            .registerContentObserver(any(), anyBoolean(), contentObserver.capture())
        contentObserver.value.onChange(selfChange)
    }

    private fun triggerEvent(event: AudioManagerEvent) {
        testScope.launch { eventsReceiver.triggerEvent(event) }
    }
+15 −1
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.systemui.volume.dagger

import android.content.ContentResolver
import android.content.Context
import android.media.AudioManager
import com.android.settingslib.bluetooth.LocalBluetoothManager
@@ -28,6 +29,7 @@ import com.android.settingslib.volume.domain.interactor.AudioModeInteractor
import com.android.settingslib.volume.domain.interactor.AudioVolumeInteractor
import com.android.settingslib.volume.shared.AudioManagerEventsReceiver
import com.android.settingslib.volume.shared.AudioManagerEventsReceiverImpl
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import dagger.Module
@@ -42,21 +44,31 @@ interface AudioModule {
    companion object {

        @Provides
        @SysUISingleton
        fun provideAudioManagerIntentsReceiver(
            @Application context: Context,
            @Application coroutineScope: CoroutineScope,
        ): AudioManagerEventsReceiver = AudioManagerEventsReceiverImpl(context, coroutineScope)

        @Provides
        @SysUISingleton
        fun provideAudioRepository(
            intentsReceiver: AudioManagerEventsReceiver,
            audioManager: AudioManager,
            contentResolver: ContentResolver,
            @Background coroutineContext: CoroutineContext,
            @Application coroutineScope: CoroutineScope,
        ): AudioRepository =
            AudioRepositoryImpl(intentsReceiver, audioManager, coroutineContext, coroutineScope)
            AudioRepositoryImpl(
                intentsReceiver,
                audioManager,
                contentResolver,
                coroutineContext,
                coroutineScope,
            )

        @Provides
        @SysUISingleton
        fun provideAudioSharingRepository(
            localBluetoothManager: LocalBluetoothManager?,
            @Background coroutineContext: CoroutineContext,
@@ -64,10 +76,12 @@ interface AudioModule {
            AudioSharingRepositoryImpl(localBluetoothManager, coroutineContext)

        @Provides
        @SysUISingleton
        fun provideAudioModeInteractor(repository: AudioRepository): AudioModeInteractor =
            AudioModeInteractor(repository)

        @Provides
        @SysUISingleton
        fun provideAudioVolumeInteractor(
            audioRepository: AudioRepository,
            notificationsSoundPolicyInteractor: NotificationsSoundPolicyInteractor,
+3 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.view.accessibility.CaptioningManager
import com.android.settingslib.view.accessibility.data.repository.CaptioningRepository
import com.android.settingslib.view.accessibility.data.repository.CaptioningRepositoryImpl
import com.android.settingslib.view.accessibility.domain.interactor.CaptioningInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import dagger.Module
@@ -33,6 +34,7 @@ interface CaptioningModule {
    companion object {

        @Provides
        @SysUISingleton
        fun provideCaptioningRepository(
            captioningManager: CaptioningManager,
            @Background coroutineContext: CoroutineContext,
@@ -41,6 +43,7 @@ interface CaptioningModule {
            CaptioningRepositoryImpl(captioningManager, coroutineContext, coroutineScope)

        @Provides
        @SysUISingleton
        fun provideCaptioningInteractor(repository: CaptioningRepository): CaptioningInteractor =
            CaptioningInteractor(repository)
    }
Loading