diff options
15 files changed, 652 insertions, 15 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioOutputInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioOutputInteractorTest.kt new file mode 100644 index 000000000000..632196ccf66d --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioOutputInteractorTest.kt @@ -0,0 +1,251 @@ +/* + * 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.domain.interactor + +import android.bluetooth.BluetoothDevice +import android.graphics.drawable.TestStubDrawable +import android.media.AudioDeviceInfo +import android.media.AudioDevicePort +import android.media.AudioManager +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.settingslib.R +import com.android.settingslib.bluetooth.CachedBluetoothDevice +import com.android.settingslib.media.BluetoothMediaDevice +import com.android.settingslib.media.MediaDevice +import com.android.settingslib.media.PhoneMediaDevice +import com.android.systemui.SysuiTestCase +import com.android.systemui.bluetooth.bluetoothAdapter +import com.android.systemui.bluetooth.cachedBluetoothDeviceManager +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.eq +import com.android.systemui.util.mockito.mock +import com.android.systemui.util.mockito.whenever +import com.android.systemui.volume.data.repository.audioRepository +import com.android.systemui.volume.domain.model.AudioOutputDevice +import com.android.systemui.volume.localMediaController +import com.android.systemui.volume.localMediaRepository +import com.android.systemui.volume.mediaControllerRepository +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@OptIn(ExperimentalCoroutinesApi::class) +@RunWith(AndroidJUnit4::class) +@SmallTest +class AudioOutputInteractorTest : SysuiTestCase() { + + private val kosmos = testKosmos() + + lateinit var underTest: AudioOutputInteractor + + @Before + fun setUp() { + with(kosmos) { + underTest = audioOutputInteractor + + with(context.orCreateTestableResources) { + addOverride(R.drawable.ic_headphone, testIcon) + addOverride(R.drawable.ic_smartphone, testIcon) + addOverride(R.drawable.ic_media_speaker_device, testIcon) + + addOverride(com.android.internal.R.drawable.ic_bt_hearing_aid, testIcon) + } + } + } + + @Test + fun inCall_builtIn_returnsCommunicationDevice() { + with(kosmos) { + testScope.runTest { + with(audioRepository) { + setMode(AudioManager.MODE_IN_CALL) + setCommunicationDevice(builtInDevice) + } + + val device by collectLastValue(underTest.currentAudioDevice) + + runCurrent() + + assertThat(device).isInstanceOf(AudioOutputDevice.BuiltIn::class.java) + assertThat(device!!.icon).isEqualTo(testIcon) + assertThat(device!!.name).isEqualTo("built_in") + } + } + } + + @Test + fun inCall_wired_returnsCommunicationDevice() { + with(kosmos) { + testScope.runTest { + with(audioRepository) { + setMode(AudioManager.MODE_IN_CALL) + setCommunicationDevice(wiredDevice) + } + + val device by collectLastValue(underTest.currentAudioDevice) + + runCurrent() + + assertThat(device).isInstanceOf(AudioOutputDevice.Wired::class.java) + assertThat(device!!.icon).isEqualTo(testIcon) + assertThat(device!!.name).isEqualTo("wired") + } + } + } + + @Test + fun inCall_bluetooth_returnsCommunicationDevice() { + with(kosmos) { + testScope.runTest { + with(audioRepository) { + setMode(AudioManager.MODE_IN_CALL) + setCommunicationDevice(btDevice) + } + val bluetoothDevice: BluetoothDevice = mock { + whenever(address).thenReturn(btDevice.address) + } + val cachedBluetoothDevice: CachedBluetoothDevice = mock { + whenever(address).thenReturn(btDevice.address) + whenever(name).thenReturn(btDevice.productName.toString()) + whenever(isHearingAidDevice).thenReturn(true) + } + whenever(bluetoothAdapter.getRemoteDevice(eq(btDevice.address))) + .thenReturn(bluetoothDevice) + whenever(cachedBluetoothDeviceManager.findDevice(any())) + .thenReturn(cachedBluetoothDevice) + + val device by collectLastValue(underTest.currentAudioDevice) + + runCurrent() + + assertThat(device).isInstanceOf(AudioOutputDevice.Bluetooth::class.java) + assertThat(device!!.icon).isEqualTo(testIcon) + assertThat(device!!.name).isEqualTo("bt") + } + } + } + + @Test + fun notInCall_builtIn_returnsMediaDevice() { + with(kosmos) { + testScope.runTest { + audioRepository.setMode(AudioManager.MODE_NORMAL) + mediaControllerRepository.setActiveSessions(listOf(localMediaController)) + localMediaRepository.updateCurrentConnectedDevice(builtInMediaDevice) + + val device by collectLastValue(underTest.currentAudioDevice) + + runCurrent() + + assertThat(device).isInstanceOf(AudioOutputDevice.BuiltIn::class.java) + assertThat(device!!.icon).isEqualTo(testIcon) + assertThat(device!!.name).isEqualTo("built_in_media") + } + } + } + + @Test + fun notInCall_wired_returnsMediaDevice() { + with(kosmos) { + testScope.runTest { + audioRepository.setMode(AudioManager.MODE_NORMAL) + mediaControllerRepository.setActiveSessions(listOf(localMediaController)) + localMediaRepository.updateCurrentConnectedDevice(wiredMediaDevice) + + val device by collectLastValue(underTest.currentAudioDevice) + + runCurrent() + + assertThat(device).isInstanceOf(AudioOutputDevice.Wired::class.java) + assertThat(device!!.icon).isEqualTo(testIcon) + assertThat(device!!.name).isEqualTo("wired_media") + } + } + } + + @Test + fun notInCall_bluetooth_returnsMediaDevice() { + with(kosmos) { + testScope.runTest { + audioRepository.setMode(AudioManager.MODE_NORMAL) + mediaControllerRepository.setActiveSessions(listOf(localMediaController)) + localMediaRepository.updateCurrentConnectedDevice(bluetoothMediaDevice) + + val device by collectLastValue(underTest.currentAudioDevice) + + runCurrent() + + assertThat(device).isInstanceOf(AudioOutputDevice.Bluetooth::class.java) + assertThat(device!!.icon).isEqualTo(testIcon) + assertThat(device!!.name).isEqualTo("bt_media") + } + } + } + + private companion object { + val testIcon = TestStubDrawable() + val builtInDevice = + AudioDeviceInfo( + AudioDevicePort.createForTesting( + AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, + "built_in", + "" + ) + ) + val wiredDevice = + AudioDeviceInfo( + AudioDevicePort.createForTesting(AudioDeviceInfo.TYPE_WIRED_HEADPHONES, "wired", "") + ) + val btDevice = + AudioDeviceInfo( + AudioDevicePort.createForTesting( + AudioDeviceInfo.TYPE_BLE_HEADSET, + "bt", + "test_address" + ) + ) + val builtInMediaDevice: MediaDevice = + mock<PhoneMediaDevice> { + whenever(name).thenReturn("built_in_media") + whenever(icon).thenReturn(testIcon) + } + val wiredMediaDevice: MediaDevice = + mock<PhoneMediaDevice> { + whenever(deviceType) + .thenReturn(MediaDevice.MediaDeviceType.TYPE_3POINT5_MM_AUDIO_DEVICE) + whenever(name).thenReturn("wired_media") + whenever(icon).thenReturn(testIcon) + } + val bluetoothMediaDevice: MediaDevice = + mock<BluetoothMediaDevice> { + whenever(name).thenReturn("bt_media") + whenever(icon).thenReturn(testIcon) + val cachedBluetoothDevice: CachedBluetoothDevice = mock { + whenever(isHearingAidDevice).thenReturn(true) + } + whenever(cachedDevice).thenReturn(cachedBluetoothDevice) + } + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioVolumeInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioVolumeInteractorTest.kt index fa79e7fc9026..675136c7cf26 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioVolumeInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioVolumeInteractorTest.kt @@ -31,7 +31,7 @@ import com.android.systemui.kosmos.testScope import com.android.systemui.statusbar.notification.domain.interactor.notificationsSoundPolicyInteractor import com.android.systemui.statusbar.notification.domain.interactor.notificationsSoundPolicyRepository import com.android.systemui.testKosmos -import com.android.systemui.volume.audioRepository +import com.android.systemui.volume.data.repository.audioRepository import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runCurrent diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/startable/AudioModeLoggerStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/startable/AudioModeLoggerStartableTest.kt index 8bb36724d1d8..89acbc8f1abd 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/startable/AudioModeLoggerStartableTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/startable/AudioModeLoggerStartableTest.kt @@ -25,8 +25,8 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.kosmos.testScope import com.android.systemui.testKosmos -import com.android.systemui.volume.audioModeInteractor -import com.android.systemui.volume.audioRepository +import com.android.systemui.volume.data.repository.audioRepository +import com.android.systemui.volume.domain.interactor.audioModeInteractor import com.android.systemui.volume.panel.ui.VolumePanelUiEvent import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -56,7 +56,7 @@ class AudioModeLoggerStartableTest : SysuiTestCase() { AudioModeLoggerStartable( applicationCoroutineScope, uiEventLogger, - audioModeInteractor + audioModeInteractor, ) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/MediaOutputAvailabilityCriteriaTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/MediaOutputAvailabilityCriteriaTest.kt index da0a2295143b..96b4dae7bb87 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/MediaOutputAvailabilityCriteriaTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/MediaOutputAvailabilityCriteriaTest.kt @@ -24,8 +24,8 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.kosmos.testScope import com.android.systemui.testKosmos -import com.android.systemui.volume.audioModeInteractor -import com.android.systemui.volume.audioRepository +import com.android.systemui.volume.data.repository.audioRepository +import com.android.systemui.volume.domain.interactor.audioModeInteractor import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runCurrent diff --git a/packages/SystemUI/src/com/android/systemui/volume/domain/interactor/AudioOutputInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/domain/interactor/AudioOutputInteractor.kt new file mode 100644 index 000000000000..ed446996a5f4 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/domain/interactor/AudioOutputInteractor.kt @@ -0,0 +1,131 @@ +/* + * 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.domain.interactor + +import android.bluetooth.BluetoothAdapter +import android.media.AudioDeviceInfo +import android.media.AudioDeviceInfo.TYPE_WIRED_HEADPHONES +import android.media.AudioDeviceInfo.TYPE_WIRED_HEADSET +import com.android.settingslib.bluetooth.CachedBluetoothDevice +import com.android.settingslib.bluetooth.LocalBluetoothManager +import com.android.settingslib.media.BluetoothMediaDevice +import com.android.settingslib.media.MediaDevice +import com.android.settingslib.media.MediaDevice.MediaDeviceType +import com.android.settingslib.volume.data.repository.AudioRepository +import com.android.settingslib.volume.domain.interactor.AudioModeInteractor +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.volume.domain.model.AudioOutputDevice +import com.android.systemui.volume.panel.component.mediaoutput.data.repository.LocalMediaRepositoryFactory +import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputInteractor +import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope +import javax.inject.Inject +import kotlin.coroutines.CoroutineContext +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn + +/** Provides a currently active audio device data. */ +@VolumePanelScope +@OptIn(ExperimentalCoroutinesApi::class) +class AudioOutputInteractor +@Inject +constructor( + audioRepository: AudioRepository, + audioModeInteractor: AudioModeInteractor, + @VolumePanelScope scope: CoroutineScope, + @Background backgroundCoroutineContext: CoroutineContext, + private val localBluetoothManager: LocalBluetoothManager?, + private val bluetoothAdapter: BluetoothAdapter?, + private val deviceIconInteractor: DeviceIconInteractor, + private val mediaOutputInteractor: MediaOutputInteractor, + private val localMediaRepositoryFactory: LocalMediaRepositoryFactory, +) { + + val currentAudioDevice: Flow<AudioOutputDevice> = + audioModeInteractor.isOngoingCall + .flatMapLatest { isOngoingCall -> + if (isOngoingCall) { + audioRepository.communicationDevice.map { communicationDevice -> + communicationDevice?.toAudioOutputDevice() + } + } else { + mediaOutputInteractor.defaultActiveMediaSession + .flatMapLatest { + localMediaRepositoryFactory + .create(it?.packageName) + .currentConnectedDevice + } + .map { mediaDevice -> mediaDevice?.toAudioOutputDevice() } + } + } + .map { it ?: AudioOutputDevice.Unknown } + .flowOn(backgroundCoroutineContext) + .stateIn(scope, SharingStarted.Eagerly, AudioOutputDevice.Unknown) + + private fun AudioDeviceInfo.toAudioOutputDevice(): AudioOutputDevice { + if (type == TYPE_WIRED_HEADPHONES || type == TYPE_WIRED_HEADSET) { + return AudioOutputDevice.Wired( + name = productName.toString(), + icon = deviceIconInteractor.loadIcon(type), + ) + } + val cachedBluetoothDevice: CachedBluetoothDevice? = + if (address.isEmpty() || localBluetoothManager == null || bluetoothAdapter == null) { + null + } else { + val remoteDevice = bluetoothAdapter.getRemoteDevice(address) + localBluetoothManager.cachedDeviceManager.findDevice(remoteDevice) + } + return cachedBluetoothDevice?.let { + AudioOutputDevice.Bluetooth( + name = it.name, + icon = deviceIconInteractor.loadIcon(it), + cachedBluetoothDevice = it, + ) + } + ?: AudioOutputDevice.BuiltIn( + name = productName.toString(), + icon = deviceIconInteractor.loadIcon(type), + ) + } + + private fun MediaDevice.toAudioOutputDevice(): AudioOutputDevice { + return when { + this is BluetoothMediaDevice -> + AudioOutputDevice.Bluetooth( + name = name, + icon = icon, + cachedBluetoothDevice = cachedDevice, + ) + deviceType == MediaDeviceType.TYPE_3POINT5_MM_AUDIO_DEVICE -> + AudioOutputDevice.Wired( + name = name, + icon = icon, + ) + else -> + AudioOutputDevice.BuiltIn( + name = name, + icon = icon, + ) + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/domain/interactor/DeviceIconInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/domain/interactor/DeviceIconInteractor.kt new file mode 100644 index 000000000000..a2f7d4a22e08 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/domain/interactor/DeviceIconInteractor.kt @@ -0,0 +1,46 @@ +/* + * 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.domain.interactor + +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.drawable.Drawable +import android.media.AudioDeviceInfo +import com.android.settingslib.R +import com.android.settingslib.bluetooth.BluetoothUtils +import com.android.settingslib.bluetooth.CachedBluetoothDevice +import com.android.settingslib.media.DeviceIconUtil +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope +import javax.inject.Inject + +/** Utility class to load an icon for a [CachedBluetoothDevice]. */ +@VolumePanelScope +@SuppressLint("UseCompatLoadingForDrawables") +class DeviceIconInteractor @Inject constructor(@Application private val context: Context) { + + private val iconUtil: DeviceIconUtil = DeviceIconUtil(context) + + fun loadIcon(@AudioDeviceInfo.AudioDeviceType type: Int): Drawable? = + context.getDrawable(iconUtil.getIconResIdFromAudioDeviceType(type)) + + fun loadIcon(cachedDevice: CachedBluetoothDevice): Drawable? { + return if (BluetoothUtils.isAdvancedUntetheredDevice(cachedDevice.device)) + context.getDrawable(R.drawable.ic_earbuds_advanced) + else BluetoothUtils.getBtClassDrawableWithDescription(context, cachedDevice).first + } +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/domain/model/AudioOutputDevice.kt b/packages/SystemUI/src/com/android/systemui/volume/domain/model/AudioOutputDevice.kt new file mode 100644 index 000000000000..ba0b08210799 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/domain/model/AudioOutputDevice.kt @@ -0,0 +1,55 @@ +/* + * 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.domain.model + +import android.graphics.drawable.Drawable +import com.android.settingslib.bluetooth.CachedBluetoothDevice + +/** Models an audio output device. */ +sealed interface AudioOutputDevice { + + val name: String + val icon: Drawable? + + /** Models a built audio output device. */ + data class BuiltIn( + override val name: String, + override val icon: Drawable?, + ) : AudioOutputDevice + + /** Models a wired audio output device. */ + data class Wired( + override val name: String, + override val icon: Drawable?, + ) : AudioOutputDevice + + /** Models a bluetooth audio output device. */ + data class Bluetooth( + override val name: String, + override val icon: Drawable?, + val cachedBluetoothDevice: CachedBluetoothDevice, + ) : AudioOutputDevice + + /** Models a state when the current audio output device is unknown. */ + data object Unknown : AudioOutputDevice { + override val name: String + get() = error("Unsupported for unknown device") + + override val icon: Drawable + get() = error("Unsupported for unknown device") + } +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/BluetoothAdapterKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/BluetoothAdapterKosmos.kt new file mode 100644 index 000000000000..854548c2509e --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/BluetoothAdapterKosmos.kt @@ -0,0 +1,23 @@ +/* + * 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.bluetooth + +import android.bluetooth.BluetoothAdapter +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.util.mockito.mock + +var Kosmos.bluetoothAdapter: BluetoothAdapter by Kosmos.Fixture { mock {} } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/CachedBluetoothDeviceManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/CachedBluetoothDeviceManagerKosmos.kt new file mode 100644 index 000000000000..07f0995f92cb --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/CachedBluetoothDeviceManagerKosmos.kt @@ -0,0 +1,23 @@ +/* + * 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.bluetooth + +import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.util.mockito.mock + +var Kosmos.cachedBluetoothDeviceManager: CachedBluetoothDeviceManager by Kosmos.Fixture { mock {} } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/LocalBluetoothManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/LocalBluetoothManagerKosmos.kt new file mode 100644 index 000000000000..eef89e7dac68 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/LocalBluetoothManagerKosmos.kt @@ -0,0 +1,27 @@ +/* + * 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.bluetooth + +import com.android.settingslib.bluetooth.LocalBluetoothManager +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.util.mockito.mock +import com.android.systemui.util.mockito.whenever + +var Kosmos.localBluetoothManager: LocalBluetoothManager? by + Kosmos.Fixture { + mock { whenever(cachedDeviceManager).thenReturn(cachedBluetoothDeviceManager) } + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/AudioRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/AudioRepositoryKosmos.kt new file mode 100644 index 000000000000..5cf214a4e04a --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/AudioRepositoryKosmos.kt @@ -0,0 +1,21 @@ +/* + * 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.data.repository + +import com.android.systemui.kosmos.Kosmos + +val Kosmos.audioRepository by Kosmos.Fixture { FakeAudioRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioRepository.kt index 4788624bdf02..617fc5258ec7 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioRepository.kt @@ -30,16 +30,14 @@ import kotlinx.coroutines.flow.update class FakeAudioRepository : AudioRepository { private val mutableMode = MutableStateFlow(0) - override val mode: StateFlow<Int> - get() = mutableMode.asStateFlow() + override val mode: StateFlow<Int> = mutableMode.asStateFlow() private val mutableRingerMode = MutableStateFlow(RingerMode(0)) - override val ringerMode: StateFlow<RingerMode> - get() = mutableRingerMode.asStateFlow() + override val ringerMode: StateFlow<RingerMode> = mutableRingerMode.asStateFlow() private val mutableCommunicationDevice = MutableStateFlow<AudioDeviceInfo?>(null) - override val communicationDevice: StateFlow<AudioDeviceInfo?> - get() = mutableCommunicationDevice.asStateFlow() + override val communicationDevice: StateFlow<AudioDeviceInfo?> = + mutableCommunicationDevice.asStateFlow() private val models: MutableMap<AudioStream, MutableStateFlow<AudioStreamModel>> = mutableMapOf() private val lastAudibleVolumes: MutableMap<AudioStream, Int> = mutableMapOf() diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/VolumeKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/domain/interactor/AudioModeInteractorKosmos.kt index 5e1f85c70a1b..99354be97fcb 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/VolumeKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/domain/interactor/AudioModeInteractorKosmos.kt @@ -14,11 +14,10 @@ * limitations under the License. */ -package com.android.systemui.volume +package com.android.systemui.volume.domain.interactor import com.android.settingslib.volume.domain.interactor.AudioModeInteractor import com.android.systemui.kosmos.Kosmos -import com.android.systemui.volume.data.repository.FakeAudioRepository +import com.android.systemui.volume.data.repository.audioRepository -val Kosmos.audioRepository by Kosmos.Fixture { FakeAudioRepository() } val Kosmos.audioModeInteractor by Kosmos.Fixture { AudioModeInteractor(audioRepository) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/domain/interactor/AudioOutputInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/domain/interactor/AudioOutputInteractorKosmos.kt new file mode 100644 index 000000000000..1b18ff5b59e2 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/domain/interactor/AudioOutputInteractorKosmos.kt @@ -0,0 +1,40 @@ +/* + * 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.domain.interactor + +import com.android.systemui.bluetooth.bluetoothAdapter +import com.android.systemui.bluetooth.localBluetoothManager +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.testScope +import com.android.systemui.volume.data.repository.audioRepository +import com.android.systemui.volume.localMediaRepositoryFactory +import com.android.systemui.volume.mediaOutputInteractor + +val Kosmos.audioOutputInteractor by + Kosmos.Fixture { + AudioOutputInteractor( + audioRepository, + audioModeInteractor, + testScope.backgroundScope, + testScope.testScheduler, + localBluetoothManager, + bluetoothAdapter, + deviceIconInteractor, + mediaOutputInteractor, + localMediaRepositoryFactory, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/domain/interactor/DeviceIconInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/domain/interactor/DeviceIconInteractorKosmos.kt new file mode 100644 index 000000000000..0a27c2a2e849 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/domain/interactor/DeviceIconInteractorKosmos.kt @@ -0,0 +1,23 @@ +/* + * 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.domain.interactor + +import android.content.applicationContext +import com.android.systemui.kosmos.Kosmos + +var Kosmos.deviceIconInteractor: DeviceIconInteractor by + Kosmos.Fixture { DeviceIconInteractor(applicationContext) } |