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