1 /* 2 * Copyright (C) 2023 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 18 package com.android.systemui.keyguard.data.quickaffordance 19 20 import android.content.Context 21 import android.media.AudioManager 22 import androidx.lifecycle.MutableLiveData 23 import androidx.lifecycle.Observer 24 import androidx.test.ext.junit.runners.AndroidJUnit4 25 import androidx.test.filters.SmallTest 26 import com.android.systemui.SysuiTestCase 27 import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository 28 import com.android.systemui.settings.UserFileManager 29 import com.android.systemui.settings.UserTracker 30 import com.android.systemui.util.RingerModeTracker 31 import com.android.systemui.util.mockito.any 32 import com.android.systemui.util.mockito.argumentCaptor 33 import com.android.systemui.util.mockito.eq 34 import com.android.systemui.util.mockito.mock 35 import com.android.systemui.util.mockito.whenever 36 import kotlinx.coroutines.ExperimentalCoroutinesApi 37 import kotlinx.coroutines.cancelChildren 38 import kotlinx.coroutines.flow.MutableStateFlow 39 import kotlinx.coroutines.test.StandardTestDispatcher 40 import kotlinx.coroutines.test.TestDispatcher 41 import kotlinx.coroutines.test.TestScope 42 import kotlinx.coroutines.test.runCurrent 43 import kotlinx.coroutines.test.runTest 44 import org.junit.Assert.assertEquals 45 46 import org.junit.Before 47 import org.junit.Test 48 import org.junit.runner.RunWith 49 import org.mockito.Mock 50 import org.mockito.Mockito.verify 51 import org.mockito.Mockito.verifyZeroInteractions 52 import org.mockito.MockitoAnnotations 53 54 @OptIn(ExperimentalCoroutinesApi::class) 55 @SmallTest 56 @RunWith(AndroidJUnit4::class) 57 class MuteQuickAffordanceCoreStartableTest : SysuiTestCase() { 58 59 @Mock 60 private lateinit var userTracker: UserTracker 61 @Mock 62 private lateinit var ringerModeTracker: RingerModeTracker 63 @Mock 64 private lateinit var userFileManager: UserFileManager 65 @Mock 66 private lateinit var keyguardQuickAffordanceRepository: KeyguardQuickAffordanceRepository 67 68 private lateinit var testDispatcher: TestDispatcher 69 private lateinit var testScope: TestScope 70 71 private lateinit var underTest: MuteQuickAffordanceCoreStartable 72 73 @Before setUpnull74 fun setUp() { 75 MockitoAnnotations.initMocks(this) 76 77 val config: KeyguardQuickAffordanceConfig = mock() 78 whenever(config.key).thenReturn(BuiltInKeyguardQuickAffordanceKeys.MUTE) 79 80 val emission = MutableStateFlow(mapOf("testQuickAffordanceKey" to listOf(config))) 81 whenever(keyguardQuickAffordanceRepository.selections).thenReturn(emission) 82 83 testDispatcher = StandardTestDispatcher() 84 testScope = TestScope(testDispatcher) 85 86 underTest = MuteQuickAffordanceCoreStartable( 87 userTracker, 88 ringerModeTracker, 89 userFileManager, 90 keyguardQuickAffordanceRepository, 91 testScope.backgroundScope, 92 testDispatcher, 93 ) 94 } 95 96 @Test <lambda>null97 fun callToKeyguardQuickAffordanceRepository() = testScope.runTest { 98 //given 99 val ringerModeInternal = mock<MutableLiveData<Int>>() 100 whenever(ringerModeTracker.ringerModeInternal).thenReturn(ringerModeInternal) 101 102 //when 103 underTest.start() 104 runCurrent() 105 106 //then 107 verify(keyguardQuickAffordanceRepository).selections 108 coroutineContext.cancelChildren() 109 } 110 111 @Test <lambda>null112 fun ringerModeIsChangedToSILENT_doNotSaveToSharedPreferences() = testScope.runTest { 113 //given 114 val ringerModeInternal = mock<MutableLiveData<Int>>() 115 val observerCaptor = argumentCaptor<Observer<Int>>() 116 whenever(ringerModeTracker.ringerModeInternal).thenReturn(ringerModeInternal) 117 118 //when 119 underTest.start() 120 runCurrent() 121 verify(ringerModeInternal).observeForever(observerCaptor.capture()) 122 observerCaptor.value.onChanged(AudioManager.RINGER_MODE_SILENT) 123 124 //then 125 verifyZeroInteractions(userFileManager) 126 coroutineContext.cancelChildren() 127 } 128 129 @Test <lambda>null130 fun ringerModeInternalChangesToSomethingNotSILENT_isSetInSharedpreferences() = testScope.runTest { 131 //given 132 val newRingerMode = 99 133 val observerCaptor = argumentCaptor<Observer<Int>>() 134 val ringerModeInternal = mock<MutableLiveData<Int>>() 135 val sharedPrefs = context.getSharedPreferences("quick_affordance_mute_ringer_mode_cache_test", Context.MODE_PRIVATE) 136 whenever(ringerModeTracker.ringerModeInternal).thenReturn(ringerModeInternal) 137 whenever( 138 userFileManager.getSharedPreferences(eq("quick_affordance_mute_ringer_mode_cache"), any(), any()) 139 ).thenReturn(sharedPrefs) 140 141 //when 142 underTest.start() 143 runCurrent() 144 verify(ringerModeInternal).observeForever(observerCaptor.capture()) 145 observerCaptor.value.onChanged(newRingerMode) 146 runCurrent() 147 val result = sharedPrefs.getInt("key_last_non_silent_ringer_mode", -1) 148 149 //then 150 assertEquals(newRingerMode, result) 151 coroutineContext.cancelChildren() 152 } 153 154 @Test <lambda>null155 fun MUTEisInSelections_observeRingerModeInternal() = testScope.runTest { 156 //given 157 val ringerModeInternal = mock<MutableLiveData<Int>>() 158 whenever(ringerModeTracker.ringerModeInternal).thenReturn(ringerModeInternal) 159 160 //when 161 underTest.start() 162 runCurrent() 163 164 //then 165 verify(ringerModeInternal).observeForever(any()) 166 coroutineContext.cancelChildren() 167 } 168 169 @Test <lambda>null170 fun MUTEisInSelections2x_observeRingerModeInternal() = testScope.runTest { 171 //given 172 val config: KeyguardQuickAffordanceConfig = mock() 173 whenever(config.key).thenReturn(BuiltInKeyguardQuickAffordanceKeys.MUTE) 174 val emission = MutableStateFlow(mapOf("testKey" to listOf(config), "testkey2" to listOf(config))) 175 whenever(keyguardQuickAffordanceRepository.selections).thenReturn(emission) 176 val ringerModeInternal = mock<MutableLiveData<Int>>() 177 whenever(ringerModeTracker.ringerModeInternal).thenReturn(ringerModeInternal) 178 179 //when 180 underTest.start() 181 runCurrent() 182 183 //then 184 verify(ringerModeInternal).observeForever(any()) 185 coroutineContext.cancelChildren() 186 } 187 188 @Test <lambda>null189 fun MUTEisNotInSelections_stopObservingRingerModeInternal() = testScope.runTest { 190 //given 191 val config: KeyguardQuickAffordanceConfig = mock() 192 whenever(config.key).thenReturn("notmutequickaffordance") 193 val emission = MutableStateFlow(mapOf("testKey" to listOf(config))) 194 whenever(keyguardQuickAffordanceRepository.selections).thenReturn(emission) 195 val ringerModeInternal = mock<MutableLiveData<Int>>() 196 whenever(ringerModeTracker.ringerModeInternal).thenReturn(ringerModeInternal) 197 198 //when 199 underTest.start() 200 runCurrent() 201 202 //then 203 verify(ringerModeInternal).removeObserver(any()) 204 coroutineContext.cancelChildren() 205 } 206 } 207