• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download

<lambda>null1 package com.android.systemui.keyguard
2 
3 import android.app.ActivityManager
4 import android.app.WallpaperManager
5 import android.app.WindowConfiguration
6 import android.graphics.Point
7 import android.graphics.Rect
8 import android.os.PowerManager
9 import android.platform.test.annotations.DisableFlags
10 import android.testing.TestableLooper.RunWithLooper
11 import android.view.RemoteAnimationTarget
12 import android.view.SurfaceControl
13 import android.view.SyncRtSurfaceTransactionApplier
14 import android.view.View
15 import android.view.ViewRootImpl
16 import android.view.WindowManager
17 import androidx.test.ext.junit.runners.AndroidJUnit4
18 import androidx.test.filters.SmallTest
19 import com.android.keyguard.KeyguardViewController
20 import com.android.systemui.Flags
21 import com.android.systemui.SysuiTestCase
22 import com.android.systemui.flags.FeatureFlags
23 import com.android.systemui.shared.system.smartspace.ILauncherUnlockAnimationController
24 import com.android.systemui.statusbar.NotificationShadeWindowController
25 import com.android.systemui.statusbar.SysuiStatusBarStateController
26 import com.android.systemui.statusbar.phone.BiometricUnlockController
27 import com.android.systemui.statusbar.policy.KeyguardStateController
28 import com.android.systemui.util.mockito.any
29 import com.android.systemui.util.mockito.argThat
30 import com.android.systemui.util.mockito.whenever
31 import junit.framework.Assert.assertEquals
32 import junit.framework.Assert.assertFalse
33 import junit.framework.Assert.assertTrue
34 import org.junit.After
35 import org.junit.Before
36 import org.junit.Test
37 import org.junit.runner.RunWith
38 import org.mockito.Mock
39 import org.mockito.Mockito.atLeastOnce
40 import org.mockito.Mockito.eq
41 import org.mockito.Mockito.mock
42 import org.mockito.Mockito.never
43 import org.mockito.Mockito.times
44 import org.mockito.Mockito.verify
45 import org.mockito.Mockito.verifyNoMoreInteractions
46 import org.mockito.MockitoAnnotations
47 import org.mockito.kotlin.clearInvocations
48 import java.util.function.Predicate
49 
50 @RunWith(AndroidJUnit4::class)
51 @RunWithLooper
52 @SmallTest
53 class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
54     private lateinit var keyguardUnlockAnimationController: KeyguardUnlockAnimationController
55 
56     @Mock
57     private lateinit var windowManager: WindowManager
58     @Mock
59     private lateinit var keyguardViewMediator: KeyguardViewMediator
60     @Mock
61     private lateinit var keyguardStateController: KeyguardStateController
62     @Mock
63     private lateinit var keyguardViewController: KeyguardViewController
64     @Mock
65     private lateinit var featureFlags: FeatureFlags
66     @Mock
67     private lateinit var biometricUnlockController: BiometricUnlockController
68     @Mock
69     private lateinit var surfaceTransactionApplier: SyncRtSurfaceTransactionApplier
70     @Mock
71     private lateinit var statusBarStateController: SysuiStatusBarStateController
72     @Mock
73     private lateinit var notificationShadeWindowController: NotificationShadeWindowController
74     @Mock
75     private lateinit var powerManager: PowerManager
76     @Mock
77     private lateinit var wallpaperManager: WallpaperManager
78 
79     @Mock
80     private lateinit var launcherUnlockAnimationController: ILauncherUnlockAnimationController.Stub
81 
82     private var surfaceControl1 = mock(SurfaceControl::class.java)
83     private var remoteTarget1 = RemoteAnimationTarget(
84             0 /* taskId */, 0, surfaceControl1, false, Rect(), Rect(), 0, Point(), Rect(), Rect(),
85             mock(WindowConfiguration::class.java), false, surfaceControl1, Rect(),
86             mock(ActivityManager.RunningTaskInfo::class.java), false)
87 
88     private var surfaceControl2 = mock(SurfaceControl::class.java)
89     private var remoteTarget2 = RemoteAnimationTarget(
90             1 /* taskId */, 0, surfaceControl2, false, Rect(), Rect(), 0, Point(), Rect(), Rect(),
91             mock(WindowConfiguration::class.java), false, surfaceControl2, Rect(),
92             mock(ActivityManager.RunningTaskInfo::class.java), false)
93     private lateinit var remoteAnimationTargets: Array<RemoteAnimationTarget>
94 
95     private var surfaceControlWp = mock(SurfaceControl::class.java)
96     private var wallpaperTarget = RemoteAnimationTarget(
97             2 /* taskId */, 0, surfaceControlWp, false, Rect(), Rect(), 0, Point(), Rect(), Rect(),
98             mock(WindowConfiguration::class.java), false, surfaceControlWp, Rect(),
99             mock(ActivityManager.RunningTaskInfo::class.java), false)
100     private lateinit var wallpaperTargets: Array<RemoteAnimationTarget>
101 
102     @Before
103     fun setUp() {
104         MockitoAnnotations.initMocks(this)
105         keyguardUnlockAnimationController = KeyguardUnlockAnimationController(
106             windowManager, context.resources,
107             keyguardStateController, { keyguardViewMediator }, keyguardViewController,
108             featureFlags, { biometricUnlockController }, statusBarStateController,
109             notificationShadeWindowController, powerManager, wallpaperManager
110         )
111         keyguardUnlockAnimationController.setLauncherUnlockController(
112             "", launcherUnlockAnimationController)
113 
114         whenever(keyguardViewController.viewRootImpl).thenReturn(mock(ViewRootImpl::class.java))
115         whenever(powerManager.isInteractive).thenReturn(true)
116 
117         // All of these fields are final, so we can't mock them, but are needed so that the surface
118         // appear amount setter doesn't short circuit.
119         remoteAnimationTargets = arrayOf(remoteTarget1)
120         wallpaperTargets = arrayOf(wallpaperTarget)
121 
122         // Set the surface applier to our mock so that we can verify the arguments passed to it.
123         // This applier does not have any side effects within the unlock animation controller, so
124         // this is a reasonable way to test.
125         keyguardUnlockAnimationController.surfaceTransactionApplier = surfaceTransactionApplier
126     }
127 
128     @After
129     fun tearDown() {
130         keyguardUnlockAnimationController.notifyFinishedKeyguardExitAnimation(true)
131     }
132 
133     /**
134      * If we're wake and unlocking, we are animating from the black/AOD screen to the app/launcher
135      * underneath. The LightRevealScrim will animate circularly from the fingerprint reader,
136      * revealing the app/launcher below. In this case, we want to make sure we are not animating the
137      * surface, or the user will see the wallpaper briefly as the app animates in.
138      */
139     @Test
140     @DisableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
141     fun noSurfaceAnimation_ifWakeAndUnlocking() {
142         whenever(biometricUnlockController.isWakeAndUnlock).thenReturn(true)
143 
144         keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
145             remoteAnimationTargets,
146             arrayOf(),
147             0 /* startTime */,
148             false /* requestedShowSurfaceBehindKeyguard */
149         )
150 
151         val captorSb = ArgThatCaptor<SyncRtSurfaceTransactionApplier.SurfaceParams>()
152         verify(surfaceTransactionApplier, times(1)).scheduleApply(
153                 captorSb.capture { sp -> sp.surface == surfaceControl1 })
154 
155         val params = captorSb.getLastValue()
156 
157         // We expect that we've instantly set the surface behind to alpha = 1f, and have no
158         // transforms (translate, scale) on its matrix.
159         assertEquals(1f, params.alpha)
160         assertTrue(params.matrix.isIdentity)
161 
162         // Also expect we've immediately asked the keyguard view mediator to finish the remote
163         // animation.
164         verify(keyguardViewMediator, times(1)).exitKeyguardAndFinishSurfaceBehindRemoteAnimation(
165             false /* cancelled */)
166 
167         verifyNoMoreInteractions(surfaceTransactionApplier)
168     }
169 
170     /**
171      * If we are not wake and unlocking, we expect the unlock animation to play normally.
172      */
173     @Test
174     fun surfaceAnimation_ifNotWakeAndUnlocking() {
175         whenever(biometricUnlockController.isWakeAndUnlock).thenReturn(false)
176 
177         keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
178             remoteAnimationTargets,
179             wallpaperTargets,
180             0 /* startTime */,
181             false /* requestedShowSurfaceBehindKeyguard */
182         )
183 
184         // Since the animation is running, we should not have finished the remote animation.
185         verify(keyguardViewMediator, times(0)).exitKeyguardAndFinishSurfaceBehindRemoteAnimation(
186             false /* cancelled */)
187     }
188 
189     @Test
190     fun onWakeAndUnlock_notifiesListenerWithTrue() {
191         whenever(biometricUnlockController.isWakeAndUnlock).thenReturn(true)
192         whenever(biometricUnlockController.mode).thenReturn(
193             BiometricUnlockController.MODE_WAKE_AND_UNLOCK)
194 
195         val listener = mock(
196             KeyguardUnlockAnimationController.KeyguardUnlockAnimationListener::class.java)
197         keyguardUnlockAnimationController.addKeyguardUnlockAnimationListener(listener)
198 
199         keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
200             remoteAnimationTargets,
201             wallpaperTargets,
202             0 /* startTime */,
203             false /* requestedShowSurfaceBehindKeyguard */
204         )
205 
206         verify(listener).onUnlockAnimationStarted(any(), eq(true), any(), any())
207     }
208 
209     @Test
210     fun onWakeAndUnlockFromDream_notifiesListenerWithFalse() {
211         whenever(biometricUnlockController.isWakeAndUnlock).thenReturn(true)
212         whenever(biometricUnlockController.mode).thenReturn(
213             BiometricUnlockController.MODE_WAKE_AND_UNLOCK_FROM_DREAM)
214 
215         val listener = mock(
216             KeyguardUnlockAnimationController.KeyguardUnlockAnimationListener::class.java)
217         keyguardUnlockAnimationController.addKeyguardUnlockAnimationListener(listener)
218 
219         keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
220             remoteAnimationTargets,
221             wallpaperTargets,
222             0 /* startTime */,
223             false /* requestedShowSurfaceBehindKeyguard */
224         )
225 
226         verify(listener).onUnlockAnimationStarted(any(), eq(false), any(), any())
227     }
228 
229     /**
230      * If we requested that the surface behind be made visible, and we're not flinging away the
231      * keyguard, it means that we're swiping to unlock and want the surface visible so it can follow
232      * the user's touch event as they swipe to unlock.
233      *
234      * In this case, we should verify that the surface was made visible via the alpha fade in
235      * animator, and verify that we did not start the canned animation to animate the surface in
236      * (since it's supposed to be following the touch events).
237      */
238     @Test
239     fun fadeInSurfaceBehind_ifRequestedShowSurface_butNotFlinging() {
240         whenever(keyguardStateController.isFlingingToDismissKeyguard).thenReturn(false)
241 
242         keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
243             remoteAnimationTargets,
244             wallpaperTargets,
245             0 /* startTime */,
246             true /* requestedShowSurfaceBehindKeyguard */
247         )
248 
249         assertTrue(keyguardUnlockAnimationController.surfaceBehindAlphaAnimator.isRunning)
250         assertFalse(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation())
251     }
252 
253     /**
254      * We requested the surface behind to be made visible, but we're now flinging to dismiss the
255      * keyguard. This means this was a swipe to dismiss gesture but the user flung the keyguard and
256      * lifted their finger while we were requesting the surface be made visible.
257      *
258      * In this case, we should verify that we are playing the canned unlock animation and not
259      * simply fading in the surface.
260      */
261     @Test
262     fun playCannedUnlockAnimation_ifRequestedShowSurface_andFlinging() {
263         whenever(keyguardStateController.isFlingingToDismissKeyguard).thenReturn(true)
264 
265         keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
266             remoteAnimationTargets,
267             wallpaperTargets,
268             0 /* startTime */,
269             true /* requestedShowSurfaceBehindKeyguard */
270         )
271 
272         assertTrue(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation())
273         assertFalse(keyguardUnlockAnimationController.surfaceBehindAlphaAnimator.isRunning)
274     }
275 
276     /**
277      * We never requested the surface behind to be made visible, which means no swiping to unlock
278      * ever happened and we're just playing the simple canned animation (happens via UDFPS unlock,
279      * long press on the lock icon, etc).
280      *
281      * In this case, we should verify that we are playing the canned unlock animation and not
282      * simply fading in the surface.
283      */
284     @Test
285     fun playCannedUnlockAnimation_ifDidNotRequestShowSurface() {
286         keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
287             remoteAnimationTargets,
288             wallpaperTargets,
289             0 /* startTime */,
290             false /* requestedShowSurfaceBehindKeyguard */
291         )
292 
293         assertTrue(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation())
294         assertFalse(keyguardUnlockAnimationController.surfaceBehindAlphaAnimator.isRunning)
295     }
296 
297     @Test
298     fun doNotPlayCannedUnlockAnimation_ifLaunchingApp() {
299         whenever(notificationShadeWindowController.isLaunchingActivity).thenReturn(true)
300 
301         keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
302             remoteAnimationTargets,
303             wallpaperTargets,
304             0 /* startTime */,
305             true /* requestedShowSurfaceBehindKeyguard */
306         )
307 
308         assertFalse(keyguardUnlockAnimationController.canPerformInWindowLauncherAnimations())
309         assertFalse(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation())
310     }
311 
312     @Test
313     fun playCannedUnlockAnimation_nullSmartspaceView_doesNotThrowExecption() {
314         keyguardUnlockAnimationController.lockscreenSmartspace = null
315         keyguardUnlockAnimationController.willUnlockWithInWindowLauncherAnimations = true
316 
317         keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
318                 remoteAnimationTargets,
319                 wallpaperTargets,
320                 0 /* startTime */,
321                 false /* requestedShowSurfaceBehindKeyguard */
322         )
323 
324         assertTrue(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation())
325     }
326 
327     /**
328      * If we are not wake and unlocking, we expect the unlock animation to play normally.
329      */
330     @Test
331     @DisableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
332     fun surfaceAnimation_multipleTargets() {
333         keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
334                 arrayOf(remoteTarget1, remoteTarget2),
335                 wallpaperTargets,
336                 0 /* startTime */,
337                 false /* requestedShowSurfaceBehindKeyguard */
338         )
339 
340         // Cancel the animator so we can verify only the setSurfaceBehind call below.
341         keyguardUnlockAnimationController.surfaceBehindAlphaAnimator.end()
342         clearInvocations(surfaceTransactionApplier)
343 
344         // Set appear to 50%, we'll just verify that we're not applying the identity matrix which
345         // means an animation is in progress.
346         keyguardUnlockAnimationController.setSurfaceBehindAppearAmount(0.5f)
347 
348         val captorSb = ArgThatCaptor<SyncRtSurfaceTransactionApplier.SurfaceParams>()
349         verify(surfaceTransactionApplier, times(2)).scheduleApply(captorSb
350                 .capture { sp -> sp.surface == surfaceControl1 || sp.surface == surfaceControl2 })
351         val captorWp = ArgThatCaptor<SyncRtSurfaceTransactionApplier.SurfaceParams>()
352         verify(surfaceTransactionApplier, times(1).description(
353                 "WallpaperSurface was expected to receive scheduleApply once"
354         )).scheduleApply(captorWp.capture { sp -> sp.surface == surfaceControlWp})
355 
356         val allParams = captorSb.getAllValues()
357 
358         val remainingTargets = mutableListOf(surfaceControl1, surfaceControl2)
359         allParams.forEach { params ->
360             assertTrue(!params.matrix.isIdentity)
361             remainingTargets.remove(params.surface)
362         }
363 
364         // Make sure we called applyParams with each of the surface controls once. The order does
365         // not matter, so don't explicitly check for that.
366         assertTrue(remainingTargets.isEmpty())
367 
368         // Since the animation is running, we should not have finished the remote animation.
369         verify(keyguardViewMediator, times(0)).exitKeyguardAndFinishSurfaceBehindRemoteAnimation(
370                 false /* cancelled */)
371     }
372 
373     @Test
374     @DisableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
375     fun surfaceBehindAlphaOverriddenTo0_ifNotInteractive() {
376         whenever(powerManager.isInteractive).thenReturn(false)
377 
378         keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
379                 remoteAnimationTargets,
380                 wallpaperTargets,
381                 0 /* startTime */,
382                 false /* requestedShowSurfaceBehindKeyguard */
383         )
384 
385         // Cancel the animator so we can verify only the setSurfaceBehind call below.
386         keyguardUnlockAnimationController.surfaceBehindAlphaAnimator.end()
387         clearInvocations(surfaceTransactionApplier)
388 
389         keyguardUnlockAnimationController.setSurfaceBehindAppearAmount(1f)
390         keyguardUnlockAnimationController.setWallpaperAppearAmount(1f)
391 
392         val captorSb = ArgThatCaptor<SyncRtSurfaceTransactionApplier.SurfaceParams>()
393         verify(surfaceTransactionApplier, times(1)).scheduleApply(
394                 captorSb.capture { sp -> sp.surface == surfaceControl1})
395         val captorWp = ArgThatCaptor<SyncRtSurfaceTransactionApplier.SurfaceParams>()
396         verify(surfaceTransactionApplier, atLeastOnce().description("Wallpaper surface has  not " +
397                 "received scheduleApply")).scheduleApply(
398                 captorWp.capture { sp -> sp.surface == surfaceControlWp })
399 
400         val params = captorSb.getLastValue()
401 
402         // We expect that we've set the surface behind to alpha = 0f since we're not interactive.
403         assertEquals(0f, params.alpha)
404         assertTrue(params.matrix.isIdentity)
405 
406         verifyNoMoreInteractions(surfaceTransactionApplier)
407     }
408 
409     @Test
410     @DisableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
411     fun surfaceBehindAlphaNotOverriddenTo0_ifInteractive() {
412         whenever(powerManager.isInteractive).thenReturn(true)
413 
414         keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
415                 remoteAnimationTargets,
416                 wallpaperTargets,
417                 0 /* startTime */,
418                 false /* requestedShowSurfaceBehindKeyguard */
419         )
420 
421         // Stop the animator - we just want to test whether the override is not applied.
422         keyguardUnlockAnimationController.surfaceBehindAlphaAnimator.end()
423         clearInvocations(surfaceTransactionApplier)
424 
425         keyguardUnlockAnimationController.setSurfaceBehindAppearAmount(1f)
426         keyguardUnlockAnimationController.setWallpaperAppearAmount(1f)
427 
428         val captorSb = ArgThatCaptor<SyncRtSurfaceTransactionApplier.SurfaceParams>()
429         verify(surfaceTransactionApplier, times(1)).scheduleApply(
430                 captorSb.capture { sp -> sp.surface == surfaceControl1 })
431         val captorWp = ArgThatCaptor<SyncRtSurfaceTransactionApplier.SurfaceParams>()
432         verify(surfaceTransactionApplier, atLeastOnce().description("Wallpaper surface has  not " +
433                 "received scheduleApply")).scheduleApply(
434                 captorWp.capture { sp -> sp.surface == surfaceControlWp })
435 
436         val params = captorSb.getLastValue()
437         assertEquals(1f, params.alpha)
438         assertTrue(params.matrix.isIdentity)
439         assertEquals("Wallpaper surface was expected to have opacity 1",
440                 1f, captorWp.getLastValue().alpha)
441 
442         verifyNoMoreInteractions(surfaceTransactionApplier)
443     }
444 
445     @Test
446     fun unlockToLauncherWithInWindowAnimations_ssViewIsVisible() {
447         val mockLockscreenSmartspaceView = mock(View::class.java)
448         whenever(mockLockscreenSmartspaceView.visibility).thenReturn(View.VISIBLE)
449         keyguardUnlockAnimationController.lockscreenSmartspace = mockLockscreenSmartspaceView
450 
451         keyguardUnlockAnimationController.unlockToLauncherWithInWindowAnimations()
452 
453         verify(mockLockscreenSmartspaceView).visibility = View.INVISIBLE
454     }
455 
456     @Test
457     fun unlockToLauncherWithInWindowAnimations_ssViewIsInvisible() {
458         val mockLockscreenSmartspaceView = mock(View::class.java)
459         whenever(mockLockscreenSmartspaceView.visibility).thenReturn(View.INVISIBLE)
460         keyguardUnlockAnimationController.lockscreenSmartspace = mockLockscreenSmartspaceView
461 
462         keyguardUnlockAnimationController.unlockToLauncherWithInWindowAnimations()
463 
464         verify(mockLockscreenSmartspaceView, never()).visibility = View.INVISIBLE
465     }
466 
467     @Test
468     fun unlockToLauncherWithInWindowAnimations_ssViewIsGone() {
469         val mockLockscreenSmartspaceView = mock(View::class.java)
470         whenever(mockLockscreenSmartspaceView.visibility).thenReturn(View.GONE)
471         keyguardUnlockAnimationController.lockscreenSmartspace = mockLockscreenSmartspaceView
472 
473         keyguardUnlockAnimationController.unlockToLauncherWithInWindowAnimations()
474 
475         verify(mockLockscreenSmartspaceView, never()).visibility = View.INVISIBLE
476     }
477 
478     @Test
479     fun notifyFinishedKeyguardExitAnimation_ssViewIsInvisibleAndCancelledIsTrue() {
480         val mockLockscreenSmartspaceView = mock(View::class.java)
481         whenever(mockLockscreenSmartspaceView.visibility).thenReturn(View.INVISIBLE)
482         keyguardUnlockAnimationController.lockscreenSmartspace = mockLockscreenSmartspaceView
483 
484         keyguardUnlockAnimationController.notifyFinishedKeyguardExitAnimation(true)
485 
486         verify(mockLockscreenSmartspaceView).visibility = View.VISIBLE
487     }
488 
489     @Test
490     fun notifyFinishedKeyguardExitAnimation_ssViewIsGoneAndCancelledIsTrue() {
491         val mockLockscreenSmartspaceView = mock(View::class.java)
492         whenever(mockLockscreenSmartspaceView.visibility).thenReturn(View.GONE)
493         keyguardUnlockAnimationController.lockscreenSmartspace = mockLockscreenSmartspaceView
494 
495         keyguardUnlockAnimationController.notifyFinishedKeyguardExitAnimation(true)
496 
497         verify(mockLockscreenSmartspaceView, never()).visibility = View.VISIBLE
498     }
499 
500     @Test
501     fun notifyFinishedKeyguardExitAnimation_ssViewIsInvisibleAndCancelledIsFalse() {
502         val mockLockscreenSmartspaceView = mock(View::class.java)
503         whenever(mockLockscreenSmartspaceView.visibility).thenReturn(View.INVISIBLE)
504         keyguardUnlockAnimationController.lockscreenSmartspace = mockLockscreenSmartspaceView
505 
506         keyguardUnlockAnimationController.notifyFinishedKeyguardExitAnimation(false)
507 
508         verify(mockLockscreenSmartspaceView).visibility = View.VISIBLE
509     }
510 
511     @Test
512     fun notifyFinishedKeyguardExitAnimation_ssViewIsGoneAndCancelledIsFalse() {
513         val mockLockscreenSmartspaceView = mock(View::class.java)
514         whenever(mockLockscreenSmartspaceView.visibility).thenReturn(View.GONE)
515         keyguardUnlockAnimationController.lockscreenSmartspace = mockLockscreenSmartspaceView
516 
517         keyguardUnlockAnimationController.notifyFinishedKeyguardExitAnimation(false)
518 
519         verify(mockLockscreenSmartspaceView, never()).visibility = View.VISIBLE
520     }
521 
522     private class ArgThatCaptor<T> {
523         private var allArgs: MutableList<T> = mutableListOf()
524 
525         fun capture(predicate: Predicate<T>): T {
526             return argThat{x: T ->
527                 if (predicate.test(x)) {
528                     allArgs.add(x)
529                     return@argThat true
530                 }
531                 return@argThat false
532             }
533         }
534 
535         fun getLastValue(): T {
536             return allArgs.last()
537         }
538 
539         fun getAllValues(): List<T> {
540             return allArgs
541         }
542     }
543 }
544