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 package com.android.systemui.bluetooth.qsdialog 17 18 import android.bluetooth.BluetoothDevice 19 import android.platform.test.annotations.DisableFlags 20 import android.platform.test.annotations.EnableFlags 21 import android.testing.AndroidTestingRunner 22 import android.testing.TestableLooper 23 import androidx.test.filters.SmallTest 24 import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession 25 import com.android.dx.mockito.inline.extended.StaticMockitoSession 26 import com.android.settingslib.bluetooth.BluetoothUtils 27 import com.android.settingslib.bluetooth.LeAudioProfile 28 import com.android.settingslib.flags.Flags 29 import com.android.systemui.SysuiTestCase 30 import com.android.systemui.kosmos.testDispatcher 31 import com.android.systemui.kosmos.testScope 32 import com.android.systemui.plugins.activityStarter 33 import com.android.systemui.statusbar.phone.SystemUIDialog 34 import com.android.systemui.testKosmos 35 import kotlinx.coroutines.ExperimentalCoroutinesApi 36 import kotlinx.coroutines.test.UnconfinedTestDispatcher 37 import kotlinx.coroutines.test.runTest 38 import org.junit.After 39 import org.junit.Before 40 import org.junit.Rule 41 import org.junit.Test 42 import org.junit.runner.RunWith 43 import org.mockito.ArgumentMatchers 44 import org.mockito.ArgumentMatchers.anyBoolean 45 import org.mockito.Mock 46 import org.mockito.Mockito 47 import org.mockito.Mockito.verify 48 import org.mockito.junit.MockitoJUnit 49 import org.mockito.junit.MockitoRule 50 import org.mockito.kotlin.any 51 import org.mockito.kotlin.eq 52 import org.mockito.kotlin.never 53 import org.mockito.kotlin.whenever 54 55 @SmallTest 56 @RunWith(AndroidTestingRunner::class) 57 @TestableLooper.RunWithLooper(setAsMainLooper = true) 58 @OptIn(ExperimentalCoroutinesApi::class) 59 class AudioSharingDeviceItemActionInteractorTest : SysuiTestCase() { 60 @get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule() <lambda>null61 private val kosmos = testKosmos().apply { testDispatcher = UnconfinedTestDispatcher() } 62 private lateinit var actionInteractorImpl: DeviceItemActionInteractor 63 private lateinit var mockitoSession: StaticMockitoSession 64 private lateinit var connectedAudioSharingMediaDeviceItem: DeviceItem 65 private lateinit var connectedMediaDeviceItem: DeviceItem 66 private lateinit var inAudioSharingMediaDeviceItem: DeviceItem 67 @Mock private lateinit var dialog: SystemUIDialog 68 @Mock private lateinit var leAudioProfile: LeAudioProfile 69 @Mock private lateinit var bluetoothDevice: BluetoothDevice 70 71 @Before setUpnull72 fun setUp() { 73 mockitoSession = 74 mockitoSession().initMocks(this).mockStatic(BluetoothUtils::class.java).startMocking() 75 connectedMediaDeviceItem = 76 DeviceItem( 77 type = DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE, 78 cachedBluetoothDevice = kosmos.cachedBluetoothDevice, 79 deviceName = DEVICE_NAME, 80 connectionSummary = DEVICE_CONNECTION_SUMMARY, 81 iconWithDescription = null, 82 background = null, 83 ) 84 inAudioSharingMediaDeviceItem = 85 DeviceItem( 86 type = DeviceItemType.AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE, 87 cachedBluetoothDevice = kosmos.cachedBluetoothDevice, 88 deviceName = DEVICE_NAME, 89 connectionSummary = DEVICE_CONNECTION_SUMMARY, 90 iconWithDescription = null, 91 background = null, 92 ) 93 connectedAudioSharingMediaDeviceItem = 94 DeviceItem( 95 type = DeviceItemType.AVAILABLE_AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE, 96 cachedBluetoothDevice = kosmos.cachedBluetoothDevice, 97 deviceName = DEVICE_NAME, 98 connectionSummary = DEVICE_CONNECTION_SUMMARY, 99 iconWithDescription = null, 100 background = null, 101 ) 102 actionInteractorImpl = kosmos.audioSharingDeviceItemActionInteractorImpl 103 } 104 105 @After tearDownnull106 fun tearDown() { 107 mockitoSession.finishMocking() 108 } 109 110 @Test 111 @EnableFlags(Flags.FLAG_AUDIO_SHARING_QS_DIALOG_IMPROVEMENT) testOnClick_connectedAudioSharingMediaDevice_flagOn_createDialognull112 fun testOnClick_connectedAudioSharingMediaDevice_flagOn_createDialog() { 113 with(kosmos) { 114 testScope.runTest { 115 bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true) 116 actionInteractorImpl.onClick(connectedAudioSharingMediaDeviceItem, dialog) 117 verify(dialogTransitionAnimator) 118 .showFromDialog(any(), any(), eq(null), anyBoolean()) 119 } 120 } 121 } 122 123 @Test 124 @DisableFlags(Flags.FLAG_AUDIO_SHARING_QS_DIALOG_IMPROVEMENT) testOnClick_connectedAudioSharingMediaDevice_flagOff_previewOn_createDialognull125 fun testOnClick_connectedAudioSharingMediaDevice_flagOff_previewOn_createDialog() { 126 with(kosmos) { 127 testScope.runTest { 128 whenever(BluetoothUtils.isAudioSharingPreviewEnabled(any())).thenReturn(true) 129 bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true) 130 actionInteractorImpl.onClick(connectedAudioSharingMediaDeviceItem, dialog) 131 verify(dialogTransitionAnimator) 132 .showFromDialog(any(), any(), eq(null), anyBoolean()) 133 } 134 } 135 } 136 137 @Test 138 @DisableFlags(Flags.FLAG_AUDIO_SHARING_QS_DIALOG_IMPROVEMENT) testOnClick_connectedAudioSharingMediaDevice_flagOff_shouldLaunchSettingsnull139 fun testOnClick_connectedAudioSharingMediaDevice_flagOff_shouldLaunchSettings() { 140 with(kosmos) { 141 testScope.runTest { 142 whenever(BluetoothUtils.isAudioSharingPreviewEnabled(any())).thenReturn(false) 143 bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true) 144 whenever(cachedBluetoothDevice.device).thenReturn(bluetoothDevice) 145 actionInteractorImpl.onClick(connectedAudioSharingMediaDeviceItem, dialog) 146 verify(activityStarter) 147 .postStartActivityDismissingKeyguard( 148 ArgumentMatchers.any(), 149 ArgumentMatchers.anyInt(), 150 ArgumentMatchers.any(), 151 ) 152 verify(dialogTransitionAnimator, never()) 153 .showFromDialog(any(), any(), eq(null), anyBoolean()) 154 } 155 } 156 } 157 158 @Test testOnClick_inAudioSharingMediaDevice_doNothingnull159 fun testOnClick_inAudioSharingMediaDevice_doNothing() { 160 with(kosmos) { 161 testScope.runTest { 162 bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true) 163 actionInteractorImpl.onClick(inAudioSharingMediaDeviceItem, dialog) 164 165 verify(dialogTransitionAnimator, never()) 166 .showFromDialog(any(), any(), eq(null), anyBoolean()) 167 } 168 } 169 } 170 171 @Test testOnClick_inAudioSharing_clickedDeviceHasSource_shouldNotLaunchSettingsnull172 fun testOnClick_inAudioSharing_clickedDeviceHasSource_shouldNotLaunchSettings() { 173 with(kosmos) { 174 testScope.runTest { 175 bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true) 176 whenever(cachedBluetoothDevice.uiAccessibleProfiles) 177 .thenReturn(listOf(leAudioProfile)) 178 whenever(BluetoothUtils.isBroadcasting(ArgumentMatchers.any())).thenReturn(true) 179 whenever( 180 BluetoothUtils.hasConnectedBroadcastSource( 181 ArgumentMatchers.any(), 182 ArgumentMatchers.any(), 183 ) 184 ) 185 .thenReturn(true) 186 187 actionInteractorImpl.onClick(connectedMediaDeviceItem, dialog) 188 verify(activityStarter, Mockito.never()) 189 .postStartActivityDismissingKeyguard( 190 ArgumentMatchers.any(), 191 ArgumentMatchers.anyInt(), 192 ArgumentMatchers.any(), 193 ) 194 } 195 } 196 } 197 198 @Test testOnClick_inAudioSharing_clickedDeviceNoSource_shouldLaunchSettingsnull199 fun testOnClick_inAudioSharing_clickedDeviceNoSource_shouldLaunchSettings() { 200 with(kosmos) { 201 testScope.runTest { 202 bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true) 203 whenever(cachedBluetoothDevice.device).thenReturn(bluetoothDevice) 204 whenever(cachedBluetoothDevice.uiAccessibleProfiles) 205 .thenReturn(listOf(leAudioProfile)) 206 207 whenever(BluetoothUtils.isBroadcasting(ArgumentMatchers.any())).thenReturn(true) 208 whenever( 209 BluetoothUtils.hasConnectedBroadcastSource( 210 ArgumentMatchers.any(), 211 ArgumentMatchers.any(), 212 ) 213 ) 214 .thenReturn(false) 215 216 actionInteractorImpl.onClick(connectedMediaDeviceItem, dialog) 217 verify(activityStarter) 218 .postStartActivityDismissingKeyguard( 219 ArgumentMatchers.any(), 220 ArgumentMatchers.anyInt(), 221 ArgumentMatchers.any(), 222 ) 223 } 224 } 225 } 226 227 private companion object { 228 const val DEVICE_NAME = "device" 229 const val DEVICE_CONNECTION_SUMMARY = "active" 230 } 231 } 232