Loading packages/SettingsLib/src/com/android/settingslib/media/data/repository/AudioManagerVolumeControllerExt.kt→packages/SettingsLib/src/com/android/settingslib/volume/data/model/VolumeControllerEvent.kt +47 −0 Original line number Diff line number Diff line Loading @@ -14,62 +14,9 @@ * limitations under the License. */ package com.android.settingslib.media.data.repository package com.android.settingslib.volume.data.model import android.media.AudioManager import android.media.IVolumeController import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.buffer import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.launch /** Returns [AudioManager.setVolumeController] events as a [Flow] */ fun AudioManager.volumeControllerEvents(): Flow<VolumeControllerEvent> = callbackFlow { volumeController = object : IVolumeController.Stub() { override fun displaySafeVolumeWarning(flags: Int) { launch { send(VolumeControllerEvent.DisplaySafeVolumeWarning(flags)) } } override fun volumeChanged(streamType: Int, flags: Int) { launch { send(VolumeControllerEvent.VolumeChanged(streamType, flags)) } } override fun masterMuteChanged(flags: Int) { launch { send(VolumeControllerEvent.MasterMuteChanged(flags)) } } override fun setLayoutDirection(layoutDirection: Int) { launch { send(VolumeControllerEvent.SetLayoutDirection(layoutDirection)) } } override fun dismiss() { launch { send(VolumeControllerEvent.Dismiss) } } override fun setA11yMode(mode: Int) { launch { send(VolumeControllerEvent.SetA11yMode(mode)) } } override fun displayCsdWarning( csdWarning: Int, displayDurationMs: Int, ) { launch { send( VolumeControllerEvent.DisplayCsdWarning( csdWarning, displayDurationMs, ) ) } } } awaitClose { volumeController = null } } .buffer() /** Models events received via [IVolumeController] */ sealed interface VolumeControllerEvent { Loading packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt +101 −22 Original line number Diff line number Diff line Loading @@ -22,9 +22,12 @@ import android.media.AudioDeviceInfo import android.media.AudioManager import android.media.AudioManager.AudioDeviceCategory import android.media.AudioManager.OnCommunicationDeviceChangedListener import android.media.IVolumeController import android.provider.Settings import android.util.Log import androidx.concurrent.futures.DirectExecutor import com.android.internal.util.ConcurrentUtils import com.android.settingslib.volume.data.model.VolumeControllerEvent import com.android.settingslib.volume.shared.AudioLogger import com.android.settingslib.volume.shared.AudioManagerEventsReceiver import com.android.settingslib.volume.shared.model.AudioManagerEvent Loading @@ -36,10 +39,13 @@ import kotlin.coroutines.CoroutineContext import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterIsInstance Loading Loading @@ -73,6 +79,11 @@ interface AudioRepository { */ val communicationDevice: StateFlow<AudioDeviceInfo?> /** Events from [AudioManager.setVolumeController] */ val volumeControllerEvents: Flow<VolumeControllerEvent> fun init() /** State of the [AudioStream]. */ fun getAudioStream(audioStream: AudioStream): Flow<AudioStreamModel> Loading @@ -90,8 +101,9 @@ interface AudioRepository { suspend fun setRingerMode(audioStream: AudioStream, mode: RingerMode) /** Gets audio device category. */ @AudioDeviceCategory suspend fun getBluetoothAudioDeviceCategory(bluetoothAddress: String): Int @AudioDeviceCategory suspend fun getBluetoothAudioDeviceCategory(bluetoothAddress: String): Int suspend fun notifyVolumeControllerVisible(isVisible: Boolean) } class AudioRepositoryImpl( Loading @@ -101,8 +113,10 @@ class AudioRepositoryImpl( private val backgroundCoroutineContext: CoroutineContext, private val coroutineScope: CoroutineScope, private val logger: AudioLogger, shouldUseVolumeController: Boolean, ) : AudioRepository { private val volumeController = ProducingVolumeController() private val streamSettingNames: Map<AudioStream, String> = mapOf( AudioStream(AudioManager.STREAM_VOICE_CALL) to Settings.System.VOLUME_VOICE, Loading @@ -116,6 +130,13 @@ class AudioRepositoryImpl( AudioStream(AudioManager.STREAM_ASSISTANT) to Settings.System.VOLUME_ASSISTANT, ) override val volumeControllerEvents: Flow<VolumeControllerEvent> = if (shouldUseVolumeController) { volumeController.events } else { emptyFlow() } override val mode: StateFlow<Int> = callbackFlow { val listener = AudioManager.OnModeChangedListener { newMode -> trySend(newMode) } Loading Loading @@ -159,6 +180,14 @@ class AudioRepositoryImpl( audioManager.communicationDevice, ) override fun init() { try { audioManager.volumeController = volumeController } catch (error: SecurityException) { Log.wtf("AudioManager", "Unable to set the volume controller", error) } } override fun getAudioStream(audioStream: AudioStream): Flow<AudioStreamModel> { return merge( audioManagerEventsReceiver.events.filter { Loading @@ -169,10 +198,12 @@ class AudioRepositoryImpl( } }, volumeSettingChanges(audioStream), volumeControllerEvents.filter { it is VolumeControllerEvent.VolumeChanged }, ) .conflate() .map { getCurrentAudioStream(audioStream) } .onStart { emit(getCurrentAudioStream(audioStream)) } .distinctUntilChanged() .onEach { logger.onVolumeUpdateReceived(audioStream, it) } .flowOn(backgroundCoroutineContext) } Loading Loading @@ -228,6 +259,12 @@ class AudioRepositoryImpl( } } override suspend fun notifyVolumeControllerVisible(isVisible: Boolean) { withContext(backgroundCoroutineContext) { audioManager.notifyVolumeControllerVisible(volumeController, isVisible) } } private fun getMinVolume(stream: AudioStream): Int = try { audioManager.getStreamMinVolume(stream.value) Loading @@ -253,3 +290,45 @@ class AudioRepositoryImpl( } } } private class ProducingVolumeController : IVolumeController.Stub() { private val mutableEvents = MutableSharedFlow<VolumeControllerEvent>(extraBufferCapacity = 32) val events = mutableEvents.asSharedFlow() override fun displaySafeVolumeWarning(flags: Int) { mutableEvents.tryEmit(VolumeControllerEvent.DisplaySafeVolumeWarning(flags)) } override fun volumeChanged(streamType: Int, flags: Int) { mutableEvents.tryEmit(VolumeControllerEvent.VolumeChanged(streamType, flags)) } override fun masterMuteChanged(flags: Int) { mutableEvents.tryEmit(VolumeControllerEvent.MasterMuteChanged(flags)) } override fun setLayoutDirection(layoutDirection: Int) { mutableEvents.tryEmit(VolumeControllerEvent.SetLayoutDirection(layoutDirection)) } override fun dismiss() { mutableEvents.tryEmit(VolumeControllerEvent.Dismiss) } override fun setA11yMode(mode: Int) { mutableEvents.tryEmit(VolumeControllerEvent.SetA11yMode(mode)) } override fun displayCsdWarning( csdWarning: Int, displayDurationMs: Int, ) { mutableEvents.tryEmit( VolumeControllerEvent.DisplayCsdWarning( csdWarning, displayDurationMs, ) ) } } packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/AudioRepositoryTest.kt +25 −2 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ import org.mockito.ArgumentMatchers.anyBoolean import org.mockito.ArgumentMatchers.anyInt import org.mockito.Captor import org.mockito.Mock import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations Loading Loading @@ -111,6 +112,7 @@ class AudioRepositoryTest { testScope.testScheduler, testScope.backgroundScope, logger, true, ) } Loading Loading @@ -261,8 +263,8 @@ class AudioRepositoryTest { @Test fun getBluetoothAudioDeviceCategory() { testScope.runTest { `when`(audioManager.getBluetoothAudioDeviceCategory("12:34:56:78")).thenReturn( AudioManager.AUDIO_DEVICE_CATEGORY_HEADPHONES) `when`(audioManager.getBluetoothAudioDeviceCategory("12:34:56:78")) .thenReturn(AudioManager.AUDIO_DEVICE_CATEGORY_HEADPHONES) val category = underTest.getBluetoothAudioDeviceCategory("12:34:56:78") runCurrent() Loading @@ -271,6 +273,27 @@ class AudioRepositoryTest { } } @Test fun useVolumeControllerDisabled_setVolumeController_notCalled() { testScope.runTest { underTest = AudioRepositoryImpl( eventsReceiver, audioManager, contentResolver, testScope.testScheduler, testScope.backgroundScope, logger, false, ) underTest.volumeControllerEvents.launchIn(backgroundScope) runCurrent() verify(audioManager, never()).volumeController = any() } } private fun triggerConnectedDeviceChange(communicationDevice: AudioDeviceInfo?) { verify(audioManager) .addOnCommunicationDeviceChangedListener( Loading packages/SettingsLib/tests/integ/src/com/android/settingslib/media/data/repository/AudioManagerVolumeControllerExtTest.kt→packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/AudioRepositoryVolumeControllerEventsTest.kt +22 −3 Original line number Diff line number Diff line Loading @@ -14,12 +14,15 @@ * limitations under the License. */ package com.android.settingslib.media.data.repository package com.android.settingslib.volume.data.repository import android.content.ContentResolver import android.media.AudioManager import android.media.IVolumeController import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.settingslib.volume.data.model.VolumeControllerEvent import com.android.settingslib.volume.shared.FakeAudioManagerEventsReceiver import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.launchIn Loading @@ -39,16 +42,32 @@ import org.mockito.MockitoAnnotations @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(AndroidJUnit4::class) class AudioManagerVolumeControllerExtTest { class AudioRepositoryVolumeControllerEventsTest { private val testScope = TestScope() @Captor private lateinit var volumeControllerCaptor: ArgumentCaptor<IVolumeController> @Mock private lateinit var audioManager: AudioManager @Mock private lateinit var contentResolver: ContentResolver private val logger = FakeAudioRepositoryLogger() private val eventsReceiver = FakeAudioManagerEventsReceiver() private lateinit var underTest: AudioRepository @Before fun setup() { MockitoAnnotations.initMocks(this) underTest = AudioRepositoryImpl( eventsReceiver, audioManager, contentResolver, testScope.testScheduler, testScope.backgroundScope, logger, true, ) } @Test Loading Loading @@ -83,7 +102,7 @@ class AudioManagerVolumeControllerExtTest { ) = testScope.runTest { var event: VolumeControllerEvent? = null audioManager.volumeControllerEvents().onEach { event = it }.launchIn(backgroundScope) underTest.volumeControllerEvents.onEach { event = it }.launchIn(backgroundScope) runCurrent() verify(audioManager).volumeController = volumeControllerCaptor.capture() Loading packages/SystemUI/src/com/android/systemui/volume/VolumeControllerCollector.kt→packages/SystemUI/src/com/android/systemui/volume/VolumeControllerAdapter.kt +14 −8 Original line number Diff line number Diff line Loading @@ -17,7 +17,8 @@ package com.android.systemui.volume import android.media.IVolumeController import com.android.settingslib.media.data.repository.VolumeControllerEvent import com.android.settingslib.volume.data.model.VolumeControllerEvent import com.android.settingslib.volume.data.repository.AudioRepository import com.android.systemui.dagger.qualifiers.Application import javax.inject.Inject import kotlinx.coroutines.CoroutineScope Loading @@ -29,17 +30,17 @@ import kotlinx.coroutines.launch * [com.android.settingslib.volume.data.repository.AudioRepository.volumeControllerEvents] and the * old code that uses [IVolumeController] interface directly. */ class VolumeControllerCollector class VolumeControllerAdapter @Inject constructor(@Application private val coroutineScope: CoroutineScope) { constructor( @Application private val coroutineScope: CoroutineScope, private val audioRepository: AudioRepository, ) { /** Collects [Flow] of [VolumeControllerEvent] into [IVolumeController]. */ fun collectToController( eventsFlow: Flow<VolumeControllerEvent>, controller: IVolumeController ) = fun collectToController(controller: IVolumeController) { coroutineScope.launch { eventsFlow.collect { event -> audioRepository.volumeControllerEvents.collect { event -> when (event) { is VolumeControllerEvent.VolumeChanged -> controller.volumeChanged(event.streamType, event.flags) Loading @@ -57,3 +58,8 @@ constructor(@Application private val coroutineScope: CoroutineScope) { } } } fun notifyVolumeControllerVisible(isVisible: Boolean) { coroutineScope.launch { audioRepository.notifyVolumeControllerVisible(isVisible) } } } Loading
packages/SettingsLib/src/com/android/settingslib/media/data/repository/AudioManagerVolumeControllerExt.kt→packages/SettingsLib/src/com/android/settingslib/volume/data/model/VolumeControllerEvent.kt +47 −0 Original line number Diff line number Diff line Loading @@ -14,62 +14,9 @@ * limitations under the License. */ package com.android.settingslib.media.data.repository package com.android.settingslib.volume.data.model import android.media.AudioManager import android.media.IVolumeController import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.buffer import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.launch /** Returns [AudioManager.setVolumeController] events as a [Flow] */ fun AudioManager.volumeControllerEvents(): Flow<VolumeControllerEvent> = callbackFlow { volumeController = object : IVolumeController.Stub() { override fun displaySafeVolumeWarning(flags: Int) { launch { send(VolumeControllerEvent.DisplaySafeVolumeWarning(flags)) } } override fun volumeChanged(streamType: Int, flags: Int) { launch { send(VolumeControllerEvent.VolumeChanged(streamType, flags)) } } override fun masterMuteChanged(flags: Int) { launch { send(VolumeControllerEvent.MasterMuteChanged(flags)) } } override fun setLayoutDirection(layoutDirection: Int) { launch { send(VolumeControllerEvent.SetLayoutDirection(layoutDirection)) } } override fun dismiss() { launch { send(VolumeControllerEvent.Dismiss) } } override fun setA11yMode(mode: Int) { launch { send(VolumeControllerEvent.SetA11yMode(mode)) } } override fun displayCsdWarning( csdWarning: Int, displayDurationMs: Int, ) { launch { send( VolumeControllerEvent.DisplayCsdWarning( csdWarning, displayDurationMs, ) ) } } } awaitClose { volumeController = null } } .buffer() /** Models events received via [IVolumeController] */ sealed interface VolumeControllerEvent { Loading
packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt +101 −22 Original line number Diff line number Diff line Loading @@ -22,9 +22,12 @@ import android.media.AudioDeviceInfo import android.media.AudioManager import android.media.AudioManager.AudioDeviceCategory import android.media.AudioManager.OnCommunicationDeviceChangedListener import android.media.IVolumeController import android.provider.Settings import android.util.Log import androidx.concurrent.futures.DirectExecutor import com.android.internal.util.ConcurrentUtils import com.android.settingslib.volume.data.model.VolumeControllerEvent import com.android.settingslib.volume.shared.AudioLogger import com.android.settingslib.volume.shared.AudioManagerEventsReceiver import com.android.settingslib.volume.shared.model.AudioManagerEvent Loading @@ -36,10 +39,13 @@ import kotlin.coroutines.CoroutineContext import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterIsInstance Loading Loading @@ -73,6 +79,11 @@ interface AudioRepository { */ val communicationDevice: StateFlow<AudioDeviceInfo?> /** Events from [AudioManager.setVolumeController] */ val volumeControllerEvents: Flow<VolumeControllerEvent> fun init() /** State of the [AudioStream]. */ fun getAudioStream(audioStream: AudioStream): Flow<AudioStreamModel> Loading @@ -90,8 +101,9 @@ interface AudioRepository { suspend fun setRingerMode(audioStream: AudioStream, mode: RingerMode) /** Gets audio device category. */ @AudioDeviceCategory suspend fun getBluetoothAudioDeviceCategory(bluetoothAddress: String): Int @AudioDeviceCategory suspend fun getBluetoothAudioDeviceCategory(bluetoothAddress: String): Int suspend fun notifyVolumeControllerVisible(isVisible: Boolean) } class AudioRepositoryImpl( Loading @@ -101,8 +113,10 @@ class AudioRepositoryImpl( private val backgroundCoroutineContext: CoroutineContext, private val coroutineScope: CoroutineScope, private val logger: AudioLogger, shouldUseVolumeController: Boolean, ) : AudioRepository { private val volumeController = ProducingVolumeController() private val streamSettingNames: Map<AudioStream, String> = mapOf( AudioStream(AudioManager.STREAM_VOICE_CALL) to Settings.System.VOLUME_VOICE, Loading @@ -116,6 +130,13 @@ class AudioRepositoryImpl( AudioStream(AudioManager.STREAM_ASSISTANT) to Settings.System.VOLUME_ASSISTANT, ) override val volumeControllerEvents: Flow<VolumeControllerEvent> = if (shouldUseVolumeController) { volumeController.events } else { emptyFlow() } override val mode: StateFlow<Int> = callbackFlow { val listener = AudioManager.OnModeChangedListener { newMode -> trySend(newMode) } Loading Loading @@ -159,6 +180,14 @@ class AudioRepositoryImpl( audioManager.communicationDevice, ) override fun init() { try { audioManager.volumeController = volumeController } catch (error: SecurityException) { Log.wtf("AudioManager", "Unable to set the volume controller", error) } } override fun getAudioStream(audioStream: AudioStream): Flow<AudioStreamModel> { return merge( audioManagerEventsReceiver.events.filter { Loading @@ -169,10 +198,12 @@ class AudioRepositoryImpl( } }, volumeSettingChanges(audioStream), volumeControllerEvents.filter { it is VolumeControllerEvent.VolumeChanged }, ) .conflate() .map { getCurrentAudioStream(audioStream) } .onStart { emit(getCurrentAudioStream(audioStream)) } .distinctUntilChanged() .onEach { logger.onVolumeUpdateReceived(audioStream, it) } .flowOn(backgroundCoroutineContext) } Loading Loading @@ -228,6 +259,12 @@ class AudioRepositoryImpl( } } override suspend fun notifyVolumeControllerVisible(isVisible: Boolean) { withContext(backgroundCoroutineContext) { audioManager.notifyVolumeControllerVisible(volumeController, isVisible) } } private fun getMinVolume(stream: AudioStream): Int = try { audioManager.getStreamMinVolume(stream.value) Loading @@ -253,3 +290,45 @@ class AudioRepositoryImpl( } } } private class ProducingVolumeController : IVolumeController.Stub() { private val mutableEvents = MutableSharedFlow<VolumeControllerEvent>(extraBufferCapacity = 32) val events = mutableEvents.asSharedFlow() override fun displaySafeVolumeWarning(flags: Int) { mutableEvents.tryEmit(VolumeControllerEvent.DisplaySafeVolumeWarning(flags)) } override fun volumeChanged(streamType: Int, flags: Int) { mutableEvents.tryEmit(VolumeControllerEvent.VolumeChanged(streamType, flags)) } override fun masterMuteChanged(flags: Int) { mutableEvents.tryEmit(VolumeControllerEvent.MasterMuteChanged(flags)) } override fun setLayoutDirection(layoutDirection: Int) { mutableEvents.tryEmit(VolumeControllerEvent.SetLayoutDirection(layoutDirection)) } override fun dismiss() { mutableEvents.tryEmit(VolumeControllerEvent.Dismiss) } override fun setA11yMode(mode: Int) { mutableEvents.tryEmit(VolumeControllerEvent.SetA11yMode(mode)) } override fun displayCsdWarning( csdWarning: Int, displayDurationMs: Int, ) { mutableEvents.tryEmit( VolumeControllerEvent.DisplayCsdWarning( csdWarning, displayDurationMs, ) ) } }
packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/AudioRepositoryTest.kt +25 −2 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ import org.mockito.ArgumentMatchers.anyBoolean import org.mockito.ArgumentMatchers.anyInt import org.mockito.Captor import org.mockito.Mock import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations Loading Loading @@ -111,6 +112,7 @@ class AudioRepositoryTest { testScope.testScheduler, testScope.backgroundScope, logger, true, ) } Loading Loading @@ -261,8 +263,8 @@ class AudioRepositoryTest { @Test fun getBluetoothAudioDeviceCategory() { testScope.runTest { `when`(audioManager.getBluetoothAudioDeviceCategory("12:34:56:78")).thenReturn( AudioManager.AUDIO_DEVICE_CATEGORY_HEADPHONES) `when`(audioManager.getBluetoothAudioDeviceCategory("12:34:56:78")) .thenReturn(AudioManager.AUDIO_DEVICE_CATEGORY_HEADPHONES) val category = underTest.getBluetoothAudioDeviceCategory("12:34:56:78") runCurrent() Loading @@ -271,6 +273,27 @@ class AudioRepositoryTest { } } @Test fun useVolumeControllerDisabled_setVolumeController_notCalled() { testScope.runTest { underTest = AudioRepositoryImpl( eventsReceiver, audioManager, contentResolver, testScope.testScheduler, testScope.backgroundScope, logger, false, ) underTest.volumeControllerEvents.launchIn(backgroundScope) runCurrent() verify(audioManager, never()).volumeController = any() } } private fun triggerConnectedDeviceChange(communicationDevice: AudioDeviceInfo?) { verify(audioManager) .addOnCommunicationDeviceChangedListener( Loading
packages/SettingsLib/tests/integ/src/com/android/settingslib/media/data/repository/AudioManagerVolumeControllerExtTest.kt→packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/AudioRepositoryVolumeControllerEventsTest.kt +22 −3 Original line number Diff line number Diff line Loading @@ -14,12 +14,15 @@ * limitations under the License. */ package com.android.settingslib.media.data.repository package com.android.settingslib.volume.data.repository import android.content.ContentResolver import android.media.AudioManager import android.media.IVolumeController import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.settingslib.volume.data.model.VolumeControllerEvent import com.android.settingslib.volume.shared.FakeAudioManagerEventsReceiver import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.launchIn Loading @@ -39,16 +42,32 @@ import org.mockito.MockitoAnnotations @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(AndroidJUnit4::class) class AudioManagerVolumeControllerExtTest { class AudioRepositoryVolumeControllerEventsTest { private val testScope = TestScope() @Captor private lateinit var volumeControllerCaptor: ArgumentCaptor<IVolumeController> @Mock private lateinit var audioManager: AudioManager @Mock private lateinit var contentResolver: ContentResolver private val logger = FakeAudioRepositoryLogger() private val eventsReceiver = FakeAudioManagerEventsReceiver() private lateinit var underTest: AudioRepository @Before fun setup() { MockitoAnnotations.initMocks(this) underTest = AudioRepositoryImpl( eventsReceiver, audioManager, contentResolver, testScope.testScheduler, testScope.backgroundScope, logger, true, ) } @Test Loading Loading @@ -83,7 +102,7 @@ class AudioManagerVolumeControllerExtTest { ) = testScope.runTest { var event: VolumeControllerEvent? = null audioManager.volumeControllerEvents().onEach { event = it }.launchIn(backgroundScope) underTest.volumeControllerEvents.onEach { event = it }.launchIn(backgroundScope) runCurrent() verify(audioManager).volumeController = volumeControllerCaptor.capture() Loading
packages/SystemUI/src/com/android/systemui/volume/VolumeControllerCollector.kt→packages/SystemUI/src/com/android/systemui/volume/VolumeControllerAdapter.kt +14 −8 Original line number Diff line number Diff line Loading @@ -17,7 +17,8 @@ package com.android.systemui.volume import android.media.IVolumeController import com.android.settingslib.media.data.repository.VolumeControllerEvent import com.android.settingslib.volume.data.model.VolumeControllerEvent import com.android.settingslib.volume.data.repository.AudioRepository import com.android.systemui.dagger.qualifiers.Application import javax.inject.Inject import kotlinx.coroutines.CoroutineScope Loading @@ -29,17 +30,17 @@ import kotlinx.coroutines.launch * [com.android.settingslib.volume.data.repository.AudioRepository.volumeControllerEvents] and the * old code that uses [IVolumeController] interface directly. */ class VolumeControllerCollector class VolumeControllerAdapter @Inject constructor(@Application private val coroutineScope: CoroutineScope) { constructor( @Application private val coroutineScope: CoroutineScope, private val audioRepository: AudioRepository, ) { /** Collects [Flow] of [VolumeControllerEvent] into [IVolumeController]. */ fun collectToController( eventsFlow: Flow<VolumeControllerEvent>, controller: IVolumeController ) = fun collectToController(controller: IVolumeController) { coroutineScope.launch { eventsFlow.collect { event -> audioRepository.volumeControllerEvents.collect { event -> when (event) { is VolumeControllerEvent.VolumeChanged -> controller.volumeChanged(event.streamType, event.flags) Loading @@ -57,3 +58,8 @@ constructor(@Application private val coroutineScope: CoroutineScope) { } } } fun notifyVolumeControllerVisible(isVisible: Boolean) { coroutineScope.launch { audioRepository.notifyVolumeControllerVisible(isVisible) } } }