1 /* 2 * 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.systemui.bluetooth.qsdialog 18 19 import android.testing.TestableLooper 20 import androidx.test.ext.junit.runners.AndroidJUnit4 21 import androidx.test.filters.SmallTest 22 import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession 23 import com.android.dx.mockito.inline.extended.StaticMockitoSession 24 import com.android.settingslib.bluetooth.BluetoothUtils 25 import com.android.settingslib.bluetooth.CachedBluetoothDevice 26 import com.android.settingslib.bluetooth.LocalBluetoothManager 27 import com.android.systemui.SysuiTestCase 28 import com.android.systemui.coroutines.collectLastValue 29 import com.android.systemui.kosmos.testScope 30 import com.android.systemui.lifecycle.activateIn 31 import com.android.systemui.res.R 32 import com.android.systemui.testKosmos 33 import com.android.systemui.util.mockito.whenever 34 import com.google.common.truth.Truth.assertThat 35 import kotlinx.coroutines.ExperimentalCoroutinesApi 36 import kotlinx.coroutines.flow.MutableSharedFlow 37 import kotlinx.coroutines.flow.MutableStateFlow 38 import kotlinx.coroutines.test.runCurrent 39 import kotlinx.coroutines.test.runTest 40 import org.junit.After 41 import org.junit.Before 42 import org.junit.Test 43 import org.junit.runner.RunWith 44 import org.mockito.Mock 45 46 @ExperimentalCoroutinesApi 47 @SmallTest 48 @RunWith(AndroidJUnit4::class) 49 @TestableLooper.RunWithLooper(setAsMainLooper = true) 50 class AudioSharingButtonViewModelTest : SysuiTestCase() { 51 private val kosmos = testKosmos() 52 private val testScope = kosmos.testScope 53 private val bluetoothState = MutableStateFlow(false) 54 private val deviceItemUpdate: MutableSharedFlow<List<DeviceItem>> = MutableSharedFlow() 55 @Mock private lateinit var cachedBluetoothDevice: CachedBluetoothDevice 56 @Mock private lateinit var localBluetoothManager: LocalBluetoothManager 57 @Mock private lateinit var bluetoothStateInteractor: BluetoothStateInteractor 58 @Mock private lateinit var deviceItemInteractor: DeviceItemInteractor 59 @Mock private lateinit var deviceItem: DeviceItem 60 private lateinit var mockitoSession: StaticMockitoSession 61 private lateinit var audioSharingButtonViewModel: AudioSharingButtonViewModel 62 63 @Before setUpnull64 fun setUp() { 65 mockitoSession = 66 mockitoSession().initMocks(this).mockStatic(BluetoothUtils::class.java).startMocking() 67 whenever(bluetoothStateInteractor.bluetoothStateUpdate).thenReturn(bluetoothState) 68 whenever(deviceItemInteractor.deviceItemUpdate).thenReturn(deviceItemUpdate) 69 audioSharingButtonViewModel = 70 AudioSharingButtonViewModel( 71 localBluetoothManager, 72 kosmos.audioSharingInteractor, 73 bluetoothStateInteractor, 74 deviceItemInteractor, 75 ) 76 audioSharingButtonViewModel.activateIn(testScope) 77 } 78 79 @After tearDownnull80 fun tearDown() { 81 mockitoSession.finishMocking() 82 } 83 84 @Test testButtonStateUpdate_bluetoothOff_returnGonenull85 fun testButtonStateUpdate_bluetoothOff_returnGone() { 86 testScope.runTest { 87 val actual by 88 collectLastValue(audioSharingButtonViewModel.audioSharingButtonStateUpdate) 89 kosmos.bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true) 90 91 runCurrent() 92 93 assertThat(actual).isEqualTo(AudioSharingButtonState.Gone) 94 } 95 } 96 97 @Test testButtonStateUpdate_noDevice_returnGonenull98 fun testButtonStateUpdate_noDevice_returnGone() { 99 testScope.runTest { 100 val actual by 101 collectLastValue(audioSharingButtonViewModel.audioSharingButtonStateUpdate) 102 kosmos.bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true) 103 bluetoothState.value = true 104 runCurrent() 105 106 assertThat(actual).isEqualTo(AudioSharingButtonState.Gone) 107 } 108 } 109 110 @Test testButtonStateUpdate_isBroadcasting_returnSharingAudionull111 fun testButtonStateUpdate_isBroadcasting_returnSharingAudio() { 112 testScope.runTest { 113 val actual by 114 collectLastValue(audioSharingButtonViewModel.audioSharingButtonStateUpdate) 115 kosmos.bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true) 116 bluetoothState.value = true 117 runCurrent() 118 deviceItemUpdate.emit(listOf()) 119 runCurrent() 120 kosmos.bluetoothTileDialogAudioSharingRepository.setInAudioSharing(true) 121 runCurrent() 122 123 assertThat(actual) 124 .isEqualTo( 125 AudioSharingButtonState.Visible( 126 R.string.quick_settings_bluetooth_audio_sharing_button_sharing, 127 isActive = true, 128 ) 129 ) 130 } 131 } 132 133 @Test testButtonStateUpdate_hasSource_returnGonenull134 fun testButtonStateUpdate_hasSource_returnGone() { 135 testScope.runTest { 136 val actual by 137 collectLastValue(audioSharingButtonViewModel.audioSharingButtonStateUpdate) 138 kosmos.bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true) 139 whenever(deviceItem.cachedBluetoothDevice).thenReturn(cachedBluetoothDevice) 140 whenever( 141 BluetoothUtils.hasConnectedBroadcastSource( 142 cachedBluetoothDevice, 143 localBluetoothManager, 144 ) 145 ) 146 .thenReturn(true) 147 bluetoothState.value = true 148 runCurrent() 149 deviceItemUpdate.emit(listOf(deviceItem)) 150 runCurrent() 151 152 assertThat(actual).isEqualTo(AudioSharingButtonState.Gone) 153 } 154 } 155 156 @Test testButtonStateUpdate_hasActiveDevice_returnAudioSharingnull157 fun testButtonStateUpdate_hasActiveDevice_returnAudioSharing() { 158 testScope.runTest { 159 val actual by 160 collectLastValue(audioSharingButtonViewModel.audioSharingButtonStateUpdate) 161 kosmos.bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true) 162 whenever(deviceItem.cachedBluetoothDevice).thenReturn(cachedBluetoothDevice) 163 whenever( 164 BluetoothUtils.hasConnectedBroadcastSource( 165 cachedBluetoothDevice, 166 localBluetoothManager, 167 ) 168 ) 169 .thenReturn(false) 170 whenever(BluetoothUtils.isActiveLeAudioDevice(cachedBluetoothDevice)).thenReturn(true) 171 bluetoothState.value = true 172 runCurrent() 173 deviceItemUpdate.emit(listOf(deviceItem)) 174 runCurrent() 175 176 assertThat(actual) 177 .isEqualTo( 178 AudioSharingButtonState.Visible( 179 R.string.quick_settings_bluetooth_audio_sharing_button, 180 isActive = false, 181 ) 182 ) 183 } 184 } 185 } 186