1 /* 2 * Copyright (C) 2022 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.media.muteawait 18 19 import android.content.Context 20 import android.graphics.drawable.Drawable 21 import android.media.AudioAttributes.USAGE_MEDIA 22 import android.media.AudioAttributes.USAGE_UNKNOWN 23 import android.media.AudioDeviceAttributes 24 import android.media.AudioDeviceInfo 25 import android.media.AudioManager 26 import android.media.AudioManager.MuteAwaitConnectionCallback.EVENT_CONNECTION 27 import androidx.test.ext.junit.runners.AndroidJUnit4 28 import androidx.test.filters.SmallTest 29 import com.android.settingslib.media.DeviceIconUtil 30 import com.android.settingslib.media.LocalMediaManager 31 import com.android.systemui.res.R 32 import com.android.systemui.SysuiTestCase 33 import com.android.systemui.util.concurrency.FakeExecutor 34 import com.android.systemui.util.mockito.any 35 import com.android.systemui.util.mockito.eq 36 import com.android.systemui.util.time.FakeSystemClock 37 import org.junit.Before 38 import org.junit.Test 39 import org.junit.runner.RunWith 40 import org.mockito.ArgumentCaptor 41 import org.mockito.Mock 42 import org.mockito.Mockito.never 43 import org.mockito.Mockito.reset 44 import org.mockito.Mockito.verify 45 import org.mockito.Mockito.`when` as whenever 46 import org.mockito.MockitoAnnotations 47 48 49 @SmallTest 50 @RunWith(AndroidJUnit4::class) 51 class MediaMuteAwaitConnectionManagerTest : SysuiTestCase() { 52 private lateinit var muteAwaitConnectionManager: MediaMuteAwaitConnectionManager 53 @Mock 54 private lateinit var audioManager: AudioManager 55 @Mock 56 private lateinit var deviceIconUtil: DeviceIconUtil 57 @Mock 58 private lateinit var localMediaManager: LocalMediaManager 59 @Mock 60 private lateinit var logger: MediaMuteAwaitLogger 61 private lateinit var icon: Drawable 62 63 @Before setUpnull64 fun setUp() { 65 MockitoAnnotations.initMocks(this) 66 context.addMockSystemService(Context.AUDIO_SERVICE, audioManager) 67 icon = context.getDrawable(R.drawable.ic_cake)!! 68 whenever(deviceIconUtil.getIconFromAudioDeviceType(any())).thenReturn(icon) 69 70 muteAwaitConnectionManager = MediaMuteAwaitConnectionManager( 71 FakeExecutor(FakeSystemClock()), 72 localMediaManager, 73 context, 74 deviceIconUtil, 75 logger 76 ) 77 } 78 79 @Test constructor_audioManagerCallbackNotRegisterednull80 fun constructor_audioManagerCallbackNotRegistered() { 81 verify(audioManager, never()).registerMuteAwaitConnectionCallback(any(), any()) 82 } 83 84 @Test startListening_audioManagerCallbackRegisterednull85 fun startListening_audioManagerCallbackRegistered() { 86 muteAwaitConnectionManager.startListening() 87 88 verify(audioManager).registerMuteAwaitConnectionCallback(any(), any()) 89 } 90 91 @Test stopListening_audioManagerCallbackUnregisterednull92 fun stopListening_audioManagerCallbackUnregistered() { 93 muteAwaitConnectionManager.stopListening() 94 95 verify(audioManager).unregisterMuteAwaitConnectionCallback(any()) 96 } 97 98 @Test startListening_audioManagerHasNoMuteAwaitDevice_localMediaMangerNotNotifiednull99 fun startListening_audioManagerHasNoMuteAwaitDevice_localMediaMangerNotNotified() { 100 whenever(audioManager.mutingExpectedDevice).thenReturn(null) 101 102 muteAwaitConnectionManager.startListening() 103 104 verify(localMediaManager, never()).dispatchAboutToConnectDeviceAdded(any(), any(), any()) 105 } 106 107 @Test startListening_audioManagerHasMuteAwaitDevice_localMediaMangerNotifiednull108 fun startListening_audioManagerHasMuteAwaitDevice_localMediaMangerNotified() { 109 whenever(audioManager.mutingExpectedDevice).thenReturn(DEVICE) 110 111 muteAwaitConnectionManager.startListening() 112 113 verify(localMediaManager).dispatchAboutToConnectDeviceAdded( 114 eq(DEVICE_ADDRESS), eq(DEVICE_NAME), eq(icon) 115 ) 116 } 117 118 @Test onMutedUntilConnection_notUsageMedia_localMediaManagerNotNotifiednull119 fun onMutedUntilConnection_notUsageMedia_localMediaManagerNotNotified() { 120 muteAwaitConnectionManager.startListening() 121 val muteAwaitListener = getMuteAwaitListener() 122 123 muteAwaitListener.onMutedUntilConnection(DEVICE, intArrayOf(USAGE_UNKNOWN)) 124 125 verify(localMediaManager, never()).dispatchAboutToConnectDeviceAdded(any(), any(), any()) 126 } 127 128 @Test onMutedUntilConnection_isUsageMedia_localMediaManagerNotifiednull129 fun onMutedUntilConnection_isUsageMedia_localMediaManagerNotified() { 130 muteAwaitConnectionManager.startListening() 131 val muteAwaitListener = getMuteAwaitListener() 132 133 134 muteAwaitListener.onMutedUntilConnection(DEVICE, intArrayOf(USAGE_MEDIA)) 135 136 verify(localMediaManager).dispatchAboutToConnectDeviceAdded( 137 eq(DEVICE_ADDRESS), eq(DEVICE_NAME), eq(icon) 138 ) 139 } 140 141 @Test onUnmutedEvent_noDeviceMutedBefore_localMediaManagerNotNotifiednull142 fun onUnmutedEvent_noDeviceMutedBefore_localMediaManagerNotNotified() { 143 muteAwaitConnectionManager.startListening() 144 val muteAwaitListener = getMuteAwaitListener() 145 146 muteAwaitListener.onUnmutedEvent(EVENT_CONNECTION, DEVICE, intArrayOf(USAGE_MEDIA)) 147 148 verify(localMediaManager, never()).dispatchAboutToConnectDeviceAdded(any(), any(), any()) 149 } 150 151 @Test onUnmutedEvent_notSameDevice_localMediaManagerNotNotifiednull152 fun onUnmutedEvent_notSameDevice_localMediaManagerNotNotified() { 153 muteAwaitConnectionManager.startListening() 154 val muteAwaitListener = getMuteAwaitListener() 155 muteAwaitListener.onMutedUntilConnection(DEVICE, intArrayOf(USAGE_MEDIA)) 156 reset(localMediaManager) 157 158 val otherDevice = AudioDeviceAttributes( 159 AudioDeviceAttributes.ROLE_OUTPUT, 160 AudioDeviceInfo.TYPE_USB_HEADSET, 161 "address", 162 "DifferentName", 163 listOf(), 164 listOf(), 165 ) 166 muteAwaitListener.onUnmutedEvent(EVENT_CONNECTION, otherDevice, intArrayOf(USAGE_MEDIA)) 167 168 verify(localMediaManager, never()).dispatchAboutToConnectDeviceAdded(any(), any(), any()) 169 } 170 171 @Test onUnmutedEvent_notUsageMedia_localMediaManagerNotNotifiednull172 fun onUnmutedEvent_notUsageMedia_localMediaManagerNotNotified() { 173 muteAwaitConnectionManager.startListening() 174 val muteAwaitListener = getMuteAwaitListener() 175 muteAwaitListener.onMutedUntilConnection(DEVICE, intArrayOf(USAGE_MEDIA)) 176 reset(localMediaManager) 177 178 muteAwaitListener.onUnmutedEvent(EVENT_CONNECTION, DEVICE, intArrayOf(USAGE_UNKNOWN)) 179 180 verify(localMediaManager, never()).dispatchAboutToConnectDeviceAdded(any(), any(), any()) 181 } 182 183 @Test onUnmutedEvent_sameDeviceAndUsageMedia_localMediaManagerNotifiednull184 fun onUnmutedEvent_sameDeviceAndUsageMedia_localMediaManagerNotified() { 185 muteAwaitConnectionManager.startListening() 186 val muteAwaitListener = getMuteAwaitListener() 187 muteAwaitListener.onMutedUntilConnection(DEVICE, intArrayOf(USAGE_MEDIA)) 188 reset(localMediaManager) 189 190 muteAwaitListener.onUnmutedEvent(EVENT_CONNECTION, DEVICE, intArrayOf(USAGE_MEDIA)) 191 192 verify(localMediaManager).dispatchAboutToConnectDeviceRemoved() 193 } 194 195 @Test onMutedUntilConnection_isLoggednull196 fun onMutedUntilConnection_isLogged() { 197 muteAwaitConnectionManager.startListening() 198 199 getMuteAwaitListener().onMutedUntilConnection(DEVICE, intArrayOf(USAGE_MEDIA)) 200 201 verify(logger).logMutedDeviceAdded(DEVICE_ADDRESS, DEVICE_NAME, hasMediaUsage = true) 202 } 203 204 @Test onUnmutedEvent_notMostRecentDevice_isLoggednull205 fun onUnmutedEvent_notMostRecentDevice_isLogged() { 206 muteAwaitConnectionManager.startListening() 207 208 getMuteAwaitListener().onUnmutedEvent(EVENT_CONNECTION, DEVICE, intArrayOf(USAGE_MEDIA)) 209 210 verify(logger).logMutedDeviceRemoved( 211 DEVICE_ADDRESS, DEVICE_NAME, hasMediaUsage = true, isMostRecentDevice = false 212 ) 213 } 214 215 @Test onUnmutedEvent_isMostRecentDevice_isLoggednull216 fun onUnmutedEvent_isMostRecentDevice_isLogged() { 217 muteAwaitConnectionManager.startListening() 218 val muteAwaitListener = getMuteAwaitListener() 219 220 muteAwaitListener.onMutedUntilConnection(DEVICE, intArrayOf(USAGE_MEDIA)) 221 muteAwaitListener.onUnmutedEvent(EVENT_CONNECTION, DEVICE, intArrayOf(USAGE_MEDIA)) 222 223 verify(logger).logMutedDeviceRemoved( 224 DEVICE_ADDRESS, DEVICE_NAME, hasMediaUsage = true, isMostRecentDevice = true 225 ) 226 } 227 getMuteAwaitListenernull228 private fun getMuteAwaitListener(): AudioManager.MuteAwaitConnectionCallback { 229 val listenerCaptor = ArgumentCaptor.forClass( 230 AudioManager.MuteAwaitConnectionCallback::class.java 231 ) 232 verify(audioManager).registerMuteAwaitConnectionCallback(any(), listenerCaptor.capture()) 233 return listenerCaptor.value!! 234 } 235 } 236 237 private const val DEVICE_ADDRESS = "DeviceAddress" 238 private const val DEVICE_NAME = "DeviceName" 239 private val DEVICE = AudioDeviceAttributes( 240 AudioDeviceAttributes.ROLE_OUTPUT, 241 AudioDeviceInfo.TYPE_USB_HEADSET, 242 DEVICE_ADDRESS, 243 DEVICE_NAME, 244 listOf(), 245 listOf(), 246 ) 247