• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 package com.android.systemui.keyguard.domain.interactor
18 
19 import androidx.test.ext.junit.runners.AndroidJUnit4
20 import androidx.test.filters.SmallTest
21 import com.android.systemui.RoboPilotTest
22 import com.android.systemui.SysuiTestCase
23 import com.android.systemui.coroutines.collectValues
24 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
25 import com.android.systemui.keyguard.shared.model.KeyguardState
26 import com.android.systemui.keyguard.shared.model.TransitionState
27 import com.android.systemui.keyguard.shared.model.TransitionStep
28 import com.android.systemui.util.mockito.whenever
29 import junit.framework.Assert.assertEquals
30 import kotlinx.coroutines.flow.MutableStateFlow
31 import kotlinx.coroutines.test.TestScope
32 import kotlinx.coroutines.test.runCurrent
33 import kotlinx.coroutines.test.runTest
34 import org.junit.Before
35 import org.junit.Test
36 import org.junit.runner.RunWith
37 import org.mockito.Mock
38 import org.mockito.MockitoAnnotations.initMocks
39 
40 @SmallTest
41 @RoboPilotTest
42 @RunWith(AndroidJUnit4::class)
43 @kotlinx.coroutines.ExperimentalCoroutinesApi
44 class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() {
45 
46     private lateinit var underTest: WindowManagerLockscreenVisibilityInteractor
47 
48     @Mock private lateinit var surfaceBehindInteractor: KeyguardSurfaceBehindInteractor
49     @Mock
50     private lateinit var fromLockscreenTransitionInteractor: FromLockscreenTransitionInteractor
51     @Mock
52     private lateinit var fromPrimaryBouncerTransitionInteractor:
53         FromPrimaryBouncerTransitionInteractor
54 
55     private val lockscreenSurfaceVisibilityFlow = MutableStateFlow<Boolean?>(false)
56     private val primaryBouncerSurfaceVisibilityFlow = MutableStateFlow<Boolean?>(false)
57     private val surfaceBehindIsAnimatingFlow = MutableStateFlow(false)
58 
59     private val testScope = TestScope()
60 
61     private lateinit var keyguardInteractor: KeyguardInteractor
62     private lateinit var transitionRepository: FakeKeyguardTransitionRepository
63     private lateinit var transitionInteractor: KeyguardTransitionInteractor
64 
65     @Before
setUpnull66     fun setUp() {
67         initMocks(this)
68 
69         whenever(fromLockscreenTransitionInteractor.surfaceBehindVisibility)
70             .thenReturn(lockscreenSurfaceVisibilityFlow)
71         whenever(fromPrimaryBouncerTransitionInteractor.surfaceBehindVisibility)
72             .thenReturn(primaryBouncerSurfaceVisibilityFlow)
73         whenever(surfaceBehindInteractor.isAnimatingSurface)
74             .thenReturn(surfaceBehindIsAnimatingFlow)
75 
76         transitionRepository = FakeKeyguardTransitionRepository()
77 
78         transitionInteractor =
79             KeyguardTransitionInteractorFactory.create(
80                     scope = testScope.backgroundScope,
81                     repository = transitionRepository,
82                 )
83                 .also { keyguardInteractor = it.keyguardInteractor }
84                 .keyguardTransitionInteractor
85 
86         underTest =
87             WindowManagerLockscreenVisibilityInteractor(
88                 keyguardInteractor = keyguardInteractor,
89                 transitionInteractor = transitionInteractor,
90                 surfaceBehindInteractor = surfaceBehindInteractor,
91                 fromLockscreenTransitionInteractor,
92                 fromPrimaryBouncerTransitionInteractor,
93             )
94     }
95 
96     @Test
surfaceBehindVisibility_switchesToCorrectFlownull97     fun surfaceBehindVisibility_switchesToCorrectFlow() =
98         testScope.runTest {
99             val values by collectValues(underTest.surfaceBehindVisibility)
100 
101             // Start on LOCKSCREEN.
102             transitionRepository.sendTransitionStep(
103                 TransitionStep(
104                     transitionState = TransitionState.STARTED,
105                     from = KeyguardState.AOD,
106                     to = KeyguardState.LOCKSCREEN,
107                 )
108             )
109 
110             runCurrent()
111 
112             transitionRepository.sendTransitionStep(
113                 TransitionStep(
114                     transitionState = TransitionState.FINISHED,
115                     from = KeyguardState.AOD,
116                     to = KeyguardState.LOCKSCREEN,
117                 )
118             )
119 
120             runCurrent()
121 
122             assertEquals(
123                 listOf(
124                     false, // We should start with the surface invisible on LOCKSCREEN.
125                 ),
126                 values
127             )
128 
129             val lockscreenSpecificSurfaceVisibility = true
130             lockscreenSurfaceVisibilityFlow.emit(lockscreenSpecificSurfaceVisibility)
131             transitionRepository.sendTransitionStep(
132                 TransitionStep(
133                     transitionState = TransitionState.STARTED,
134                     from = KeyguardState.LOCKSCREEN,
135                     to = KeyguardState.GONE,
136                 )
137             )
138 
139             runCurrent()
140 
141             // We started a transition from LOCKSCREEN, we should be using the value emitted by the
142             // lockscreenSurfaceVisibilityFlow.
143             assertEquals(
144                 listOf(
145                     false,
146                     lockscreenSpecificSurfaceVisibility,
147                 ),
148                 values
149             )
150 
151             // Go back to LOCKSCREEN, since we won't emit 'true' twice in a row.
152             transitionRepository.sendTransitionStep(
153                 TransitionStep(
154                     transitionState = TransitionState.STARTED,
155                     from = KeyguardState.GONE,
156                     to = KeyguardState.LOCKSCREEN,
157                 )
158             )
159             runCurrent()
160             transitionRepository.sendTransitionStep(
161                 TransitionStep(
162                     transitionState = TransitionState.FINISHED,
163                     from = KeyguardState.GONE,
164                     to = KeyguardState.LOCKSCREEN,
165                 )
166             )
167             runCurrent()
168 
169             assertEquals(
170                 listOf(
171                     false,
172                     lockscreenSpecificSurfaceVisibility,
173                     false, // FINISHED (LOCKSCREEN)
174                 ),
175                 values
176             )
177 
178             val bouncerSpecificVisibility = true
179             primaryBouncerSurfaceVisibilityFlow.emit(bouncerSpecificVisibility)
180             transitionRepository.sendTransitionStep(
181                 TransitionStep(
182                     transitionState = TransitionState.STARTED,
183                     from = KeyguardState.PRIMARY_BOUNCER,
184                     to = KeyguardState.GONE,
185                 )
186             )
187 
188             runCurrent()
189 
190             // We started a transition from PRIMARY_BOUNCER, we should be using the value emitted by
191             // the
192             // primaryBouncerSurfaceVisibilityFlow.
193             assertEquals(
194                 listOf(
195                     false,
196                     lockscreenSpecificSurfaceVisibility,
197                     false,
198                     bouncerSpecificVisibility,
199                 ),
200                 values
201             )
202         }
203 
204     @Test
testUsingGoingAwayAnimation_duringTransitionToGonenull205     fun testUsingGoingAwayAnimation_duringTransitionToGone() =
206         testScope.runTest {
207             val values by collectValues(underTest.usingKeyguardGoingAwayAnimation)
208 
209             // Start on LOCKSCREEN.
210             transitionRepository.sendTransitionStep(
211                 TransitionStep(
212                     transitionState = TransitionState.STARTED,
213                     from = KeyguardState.AOD,
214                     to = KeyguardState.LOCKSCREEN,
215                 )
216             )
217             runCurrent()
218             transitionRepository.sendTransitionStep(
219                 TransitionStep(
220                     transitionState = TransitionState.FINISHED,
221                     from = KeyguardState.AOD,
222                     to = KeyguardState.LOCKSCREEN,
223                 )
224             )
225             runCurrent()
226 
227             assertEquals(
228                 listOf(
229                     false, // Not using the animation when we're just sitting on LOCKSCREEN.
230                 ),
231                 values
232             )
233 
234             surfaceBehindIsAnimatingFlow.emit(true)
235             runCurrent()
236             transitionRepository.sendTransitionStep(
237                 TransitionStep(
238                     transitionState = TransitionState.FINISHED,
239                     from = KeyguardState.LOCKSCREEN,
240                     to = KeyguardState.GONE,
241                 )
242             )
243             runCurrent()
244 
245             assertEquals(
246                 listOf(
247                     false,
248                     true, // Still true when we're FINISHED -> GONE, since we're still animating.
249                 ),
250                 values
251             )
252 
253             surfaceBehindIsAnimatingFlow.emit(false)
254             runCurrent()
255 
256             assertEquals(
257                 listOf(
258                     false,
259                     true,
260                     false, // False once the animation ends.
261                 ),
262                 values
263             )
264         }
265 
266     @Test
testNotUsingGoingAwayAnimation_evenWhenAnimating_ifStateIsNotGonenull267     fun testNotUsingGoingAwayAnimation_evenWhenAnimating_ifStateIsNotGone() =
268         testScope.runTest {
269             val values by collectValues(underTest.usingKeyguardGoingAwayAnimation)
270 
271             // Start on LOCKSCREEN.
272             transitionRepository.sendTransitionStep(
273                 TransitionStep(
274                     transitionState = TransitionState.STARTED,
275                     from = KeyguardState.AOD,
276                     to = KeyguardState.LOCKSCREEN,
277                 )
278             )
279             runCurrent()
280             transitionRepository.sendTransitionStep(
281                 TransitionStep(
282                     transitionState = TransitionState.FINISHED,
283                     from = KeyguardState.AOD,
284                     to = KeyguardState.LOCKSCREEN,
285                 )
286             )
287             runCurrent()
288 
289             assertEquals(
290                 listOf(
291                     false, // Not using the animation when we're just sitting on LOCKSCREEN.
292                 ),
293                 values
294             )
295 
296             surfaceBehindIsAnimatingFlow.emit(true)
297             runCurrent()
298             transitionRepository.sendTransitionStep(
299                 TransitionStep(
300                     transitionState = TransitionState.STARTED,
301                     from = KeyguardState.LOCKSCREEN,
302                     to = KeyguardState.GONE,
303                 )
304             )
305             runCurrent()
306 
307             assertEquals(
308                 listOf(
309                     false,
310                     true, // We're happily animating while transitioning to gone.
311                 ),
312                 values
313             )
314 
315             // Oh no, we're still surfaceBehindAnimating=true, but no longer transitioning to GONE.
316             transitionRepository.sendTransitionStep(
317                 TransitionStep(
318                     transitionState = TransitionState.STARTED,
319                     from = KeyguardState.LOCKSCREEN,
320                     to = KeyguardState.AOD,
321                 )
322             )
323             runCurrent()
324 
325             assertEquals(
326                 listOf(
327                     false,
328                     true,
329                     false, // Despite the animator still running, this should be false.
330                 ),
331                 values
332             )
333 
334             surfaceBehindIsAnimatingFlow.emit(false)
335             runCurrent()
336 
337             assertEquals(
338                 listOf(
339                     false,
340                     true,
341                     false, // The animator ending should have no effect.
342                 ),
343                 values
344             )
345         }
346 
347     @Test
lockscreenVisibility_visibleWhenGonenull348     fun lockscreenVisibility_visibleWhenGone() =
349         testScope.runTest {
350             val values by collectValues(underTest.lockscreenVisibility)
351 
352             // Start on LOCKSCREEN.
353             transitionRepository.sendTransitionStep(
354                 TransitionStep(
355                     transitionState = TransitionState.STARTED,
356                     from = KeyguardState.AOD,
357                     to = KeyguardState.LOCKSCREEN,
358                 )
359             )
360             runCurrent()
361 
362             transitionRepository.sendTransitionStep(
363                 TransitionStep(
364                     transitionState = TransitionState.FINISHED,
365                     from = KeyguardState.AOD,
366                     to = KeyguardState.LOCKSCREEN,
367                 )
368             )
369             runCurrent()
370 
371             assertEquals(
372                 listOf(
373                     true, // Unsurprisingly, we should start with the lockscreen visible on
374                     // LOCKSCREEN.
375                 ),
376                 values
377             )
378 
379             transitionRepository.sendTransitionStep(
380                 TransitionStep(
381                     transitionState = TransitionState.STARTED,
382                     from = KeyguardState.LOCKSCREEN,
383                     to = KeyguardState.GONE,
384                 )
385             )
386             runCurrent()
387 
388             assertEquals(
389                 listOf(
390                     true, // Lockscreen remains visible while we're transitioning to GONE.
391                 ),
392                 values
393             )
394 
395             transitionRepository.sendTransitionStep(
396                 TransitionStep(
397                     transitionState = TransitionState.FINISHED,
398                     from = KeyguardState.LOCKSCREEN,
399                     to = KeyguardState.GONE,
400                 )
401             )
402             runCurrent()
403 
404             assertEquals(
405                 listOf(
406                     true,
407                     false, // Once we're fully GONE, the lockscreen should not be visible.
408                 ),
409                 values
410             )
411         }
412 }
413