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