<lambda>null1 package com.android.systemui.statusbar
2
3 import android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE
4 import android.testing.TestableLooper
5 import android.testing.TestableLooper.RunWithLooper
6 import androidx.test.ext.junit.runners.AndroidJUnit4
7 import androidx.test.filters.SmallTest
8 import com.android.systemui.ExpandHelper
9 import com.android.systemui.SysuiTestCase
10 import com.android.systemui.classifier.FalsingCollectorFake
11 import com.android.systemui.classifier.FalsingManagerFake
12 import com.android.systemui.flags.Flags
13 import com.android.systemui.flags.fakeFeatureFlagsClassic
14 import com.android.systemui.keyguard.domain.interactor.NaturalScrollingSettingObserver
15 import com.android.systemui.kosmos.testScope
16 import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager
17 import com.android.systemui.plugins.qs.QS
18 import com.android.systemui.qs.ui.adapter.FakeQSSceneAdapter
19 import com.android.systemui.res.R
20 import com.android.systemui.shade.data.repository.shadeRepository
21 import com.android.systemui.shade.domain.interactor.ShadeLockscreenInteractor
22 import com.android.systemui.shade.domain.interactor.shadeInteractor
23 import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository
24 import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel
25 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
26 import com.android.systemui.statusbar.notification.row.NotificationTestHelper
27 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
28 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
29 import com.android.systemui.statusbar.phone.CentralSurfaces
30 import com.android.systemui.statusbar.phone.KeyguardBypassController
31 import com.android.systemui.statusbar.phone.ScrimController
32 import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController
33 import com.android.systemui.statusbar.policy.fakeConfigurationController
34 import com.android.systemui.testKosmos
35 import com.android.systemui.util.mockito.any
36 import com.android.systemui.util.mockito.argumentCaptor
37 import com.android.systemui.util.mockito.mock
38 import kotlinx.coroutines.ExperimentalCoroutinesApi
39 import kotlinx.coroutines.test.runCurrent
40 import kotlinx.coroutines.test.runTest
41 import org.junit.After
42 import org.junit.Assert.assertFalse
43 import org.junit.Assert.assertNotNull
44 import org.junit.Assert.assertNull
45 import org.junit.Assert.assertTrue
46 import org.junit.Before
47 import org.junit.Rule
48 import org.junit.Test
49 import org.junit.runner.RunWith
50 import org.mockito.ArgumentMatchers.anyBoolean
51 import org.mockito.ArgumentMatchers.anyFloat
52 import org.mockito.ArgumentMatchers.anyInt
53 import org.mockito.ArgumentMatchers.anyLong
54 import org.mockito.ArgumentMatchers.eq
55 import org.mockito.ArgumentMatchers.isNull
56 import org.mockito.Mock
57 import org.mockito.Mockito
58 import org.mockito.Mockito.clearInvocations
59 import org.mockito.Mockito.never
60 import org.mockito.Mockito.verify
61 import org.mockito.Mockito.verifyNoMoreInteractions
62 import org.mockito.Mockito.`when` as whenever
63 import org.mockito.junit.MockitoJUnit
64
65 private fun <T> anyObject(): T {
66 return Mockito.anyObject<T>()
67 }
68
69 @SmallTest
70 @RunWithLooper(setAsMainLooper = true)
71 @RunWith(AndroidJUnit4::class)
72 @OptIn(ExperimentalCoroutinesApi::class)
73 class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
74 private val kosmos =
<lambda>null75 testKosmos().apply {
76 fakeFeatureFlagsClassic.apply { set(Flags.FULL_SCREEN_USER_SWITCHER, false) }
77 }
78 private lateinit var transitionController: LockscreenShadeTransitionController
79 private val configurationController = kosmos.fakeConfigurationController
80 private val disableFlagsRepository = kosmos.fakeDisableFlagsRepository
81 private val testScope = kosmos.testScope
82
<lambda>null83 private val qsSceneAdapter = FakeQSSceneAdapter({ mock() })
84
85 lateinit var row: ExpandableNotificationRow
86
87 @Mock lateinit var centralSurfaces: CentralSurfaces
88 @Mock lateinit var depthController: NotificationShadeDepthController
89 @Mock lateinit var expandHelperCallback: ExpandHelper.Callback
90 @Mock lateinit var keyguardBypassController: KeyguardBypassController
91 @Mock lateinit var lockScreenUserManager: NotificationLockscreenUserManager
92 @Mock lateinit var mediaHierarchyManager: MediaHierarchyManager
93 @Mock lateinit var nsslController: NotificationStackScrollLayoutController
94 @Mock lateinit var qS: QS
95 @Mock lateinit var qsTransitionController: LockscreenShadeQsTransitionController
96 @Mock lateinit var scrimController: ScrimController
97 @Mock lateinit var shadeLockscreenInteractor: ShadeLockscreenInteractor
98 @Mock lateinit var singleShadeOverScroller: SingleShadeLockScreenOverScroller
99 @Mock lateinit var splitShadeOverScroller: SplitShadeLockScreenOverScroller
100 @Mock lateinit var stackscroller: NotificationStackScrollLayout
101 @Mock lateinit var statusbarStateController: SysuiStatusBarStateController
102 @Mock lateinit var transitionControllerCallback: LockscreenShadeTransitionController.Callback
103 @Mock lateinit var naturalScrollingSettingObserver: NaturalScrollingSettingObserver
104
105 @JvmField @Rule val mockito = MockitoJUnit.rule()
106
107 @Before
setupnull108 fun setup() {
109 val helper = NotificationTestHelper(mContext, mDependency, TestableLooper.get(this))
110 row = helper.createRow()
111 context
112 .getOrCreateTestableResources()
113 .addOverride(R.bool.config_use_split_notification_shade, false)
114 context
115 .getOrCreateTestableResources()
116 .addOverride(R.dimen.lockscreen_shade_depth_controller_transition_distance, 100)
117
118 whenever(nsslController.view).thenReturn(stackscroller)
119 whenever(nsslController.expandHelperCallback).thenReturn(expandHelperCallback)
120 whenever(statusbarStateController.state).thenReturn(StatusBarState.KEYGUARD)
121 whenever(nsslController.isInLockedDownShade).thenReturn(false)
122 whenever(qS.isFullyCollapsed).thenReturn(true)
123 whenever(lockScreenUserManager.userAllowsPrivateNotificationsInPublic(anyInt()))
124 .thenReturn(true)
125 whenever(lockScreenUserManager.shouldShowLockscreenNotifications()).thenReturn(true)
126 whenever(lockScreenUserManager.isLockscreenPublicMode(anyInt())).thenReturn(true)
127 whenever(keyguardBypassController.bypassEnabled).thenReturn(false)
128 whenever(naturalScrollingSettingObserver.isNaturalScrollingEnabled).thenReturn(true)
129
130 transitionController =
131 LockscreenShadeTransitionController(
132 statusBarStateController = statusbarStateController,
133 logger = mock(),
134 keyguardBypassController = keyguardBypassController,
135 lockScreenUserManager = lockScreenUserManager,
136 falsingCollector = FalsingCollectorFake(),
137 ambientState = mock(),
138 mediaHierarchyManager = mediaHierarchyManager,
139 scrimTransitionController =
140 LockscreenShadeScrimTransitionController(
141 scrimController = scrimController,
142 context = context,
143 configurationController = configurationController,
144 dumpManager = mock(),
145 splitShadeStateController = ResourcesSplitShadeStateController(),
146 ),
147 keyguardTransitionControllerFactory = { notificationPanelController ->
148 LockscreenShadeKeyguardTransitionController(
149 mediaHierarchyManager = mediaHierarchyManager,
150 shadeLockscreenInteractor = notificationPanelController,
151 context = context,
152 configurationController = configurationController,
153 dumpManager = mock(),
154 splitShadeStateController = ResourcesSplitShadeStateController(),
155 )
156 },
157 depthController = depthController,
158 context = context,
159 splitShadeOverScrollerFactory = { _, _ -> splitShadeOverScroller },
160 singleShadeOverScrollerFactory = { singleShadeOverScroller },
161 activityStarter = mock(),
162 wakefulnessLifecycle = mock(),
163 configurationController = configurationController,
164 falsingManager = FalsingManagerFake(),
165 dumpManager = mock(),
166 qsTransitionControllerFactory = { qsTransitionController },
167 shadeRepository = kosmos.shadeRepository,
168 shadeInteractor = kosmos.shadeInteractor,
169 splitShadeStateController = ResourcesSplitShadeStateController(),
170 shadeLockscreenInteractorLazy = { shadeLockscreenInteractor },
171 naturalScrollingSettingObserver = naturalScrollingSettingObserver,
172 lazyQSSceneAdapter = { qsSceneAdapter },
173 )
174
175 transitionController.addCallback(transitionControllerCallback)
176 transitionController.centralSurfaces = centralSurfaces
177 transitionController.qS = qS
178 transitionController.setStackScroller(nsslController)
179 clearInvocations(centralSurfaces)
180
181 testScope.runCurrent()
182 }
183
184 @After
tearDownnull185 fun tearDown() {
186 transitionController.dragDownAnimator?.cancel()
187 }
188
189 @Test
testCantDragDownWhenQSExpandednull190 fun testCantDragDownWhenQSExpanded() =
191 testScope.runTest {
192 assertTrue("Can't drag down on keyguard", transitionController.canDragDown())
193 whenever(qS.isFullyCollapsed).thenReturn(false)
194 assertFalse("Can drag down when QS is expanded", transitionController.canDragDown())
195 }
196
197 @Test
testCanDragDownInLockedDownShadenull198 fun testCanDragDownInLockedDownShade() =
199 testScope.runTest {
200 whenever(statusbarStateController.state).thenReturn(StatusBarState.SHADE_LOCKED)
201 assertFalse("Can drag down in shade locked", transitionController.canDragDown())
202 whenever(nsslController.isInLockedDownShade).thenReturn(true)
203 assertTrue("Can't drag down in locked down shade", transitionController.canDragDown())
204 }
205
206 @Test
testGoingToLockedShadenull207 fun testGoingToLockedShade() =
208 testScope.runTest {
209 transitionController.goToLockedShade(null)
210 verify(statusbarStateController).setState(StatusBarState.SHADE_LOCKED)
211 }
212
213 @Test
testWakingToShadeLockedWhenDozingnull214 fun testWakingToShadeLockedWhenDozing() =
215 testScope.runTest {
216 whenever(statusbarStateController.isDozing).thenReturn(true)
217 transitionController.goToLockedShade(null)
218 verify(statusbarStateController).setState(StatusBarState.SHADE_LOCKED)
219 assertTrue("Not waking to shade locked", transitionController.isWakingToShadeLocked)
220 }
221
222 @Test
testNotWakingToShadeLockedWhenNotDozingnull223 fun testNotWakingToShadeLockedWhenNotDozing() =
224 testScope.runTest {
225 whenever(statusbarStateController.isDozing).thenReturn(false)
226 transitionController.goToLockedShade(null)
227 verify(statusbarStateController).setState(StatusBarState.SHADE_LOCKED)
228 assertFalse(
229 "Waking to shade locked when not dozing",
230 transitionController.isWakingToShadeLocked,
231 )
232 }
233
234 @Test
testGoToLockedShadeOnlyOnKeyguardnull235 fun testGoToLockedShadeOnlyOnKeyguard() =
236 testScope.runTest {
237 whenever(statusbarStateController.state).thenReturn(StatusBarState.SHADE_LOCKED)
238 transitionController.goToLockedShade(null)
239 whenever(statusbarStateController.state).thenReturn(StatusBarState.SHADE)
240 transitionController.goToLockedShade(null)
241 verify(statusbarStateController, never()).setState(anyInt())
242 }
243
244 @Test
testDontGoWhenShadeDisablednull245 fun testDontGoWhenShadeDisabled() =
246 testScope.runTest {
247 disableFlagsRepository.disableFlags.value =
248 DisableFlagsModel(disable2 = DISABLE2_NOTIFICATION_SHADE)
249 testScope.runCurrent()
250 transitionController.goToLockedShade(null)
251 verify(statusbarStateController, never()).setState(anyInt())
252 }
253
254 @Test
testUserExpandsViewOnGoingToFullShadenull255 fun testUserExpandsViewOnGoingToFullShade() =
256 testScope.runTest {
257 assertFalse("Row shouldn't be user expanded yet", row.isUserExpanded)
258 transitionController.goToLockedShade(row)
259 assertTrue("Row wasn't user expanded on drag down", row.isUserExpanded)
260 }
261
262 @Test
testTriggeringBouncerNoNotificationsOnLockscreennull263 fun testTriggeringBouncerNoNotificationsOnLockscreen() =
264 testScope.runTest {
265 whenever(lockScreenUserManager.shouldShowLockscreenNotifications()).thenReturn(false)
266 transitionController.goToLockedShade(null)
267 verify(statusbarStateController, never()).setState(anyInt())
268 verify(statusbarStateController).setLeaveOpenOnKeyguardHide(true)
269 verify(centralSurfaces)
270 .showBouncerWithDimissAndCancelIfKeyguard(anyObject(), anyObject())
271 }
272
273 @Test
testGoToLockedShadeCreatesQSAnimationnull274 fun testGoToLockedShadeCreatesQSAnimation() =
275 testScope.runTest {
276 transitionController.goToLockedShade(null)
277 verify(statusbarStateController).setState(StatusBarState.SHADE_LOCKED)
278 verify(shadeLockscreenInteractor).transitionToExpandedShade(anyLong())
279 assertNotNull(transitionController.dragDownAnimator)
280 }
281
282 @Test
testGoToLockedShadeDoesntCreateQSAnimationnull283 fun testGoToLockedShadeDoesntCreateQSAnimation() =
284 testScope.runTest {
285 transitionController.goToLockedShade(null, needsQSAnimation = false)
286 verify(statusbarStateController).setState(StatusBarState.SHADE_LOCKED)
287 verify(shadeLockscreenInteractor).transitionToExpandedShade(anyLong())
288 assertNull(transitionController.dragDownAnimator)
289 }
290
291 @Test
testGoToLockedShadeAlwaysCreatesQSAnimationInSplitShadenull292 fun testGoToLockedShadeAlwaysCreatesQSAnimationInSplitShade() =
293 testScope.runTest {
294 enableSplitShade()
295 transitionController.goToLockedShade(null, needsQSAnimation = true)
296 verify(shadeLockscreenInteractor).transitionToExpandedShade(anyLong())
297 assertNotNull(transitionController.dragDownAnimator)
298 }
299
300 @Test
testGoToLockedShadeCancelDoesntLeaveShadeOpenOnKeyguardHidenull301 fun testGoToLockedShadeCancelDoesntLeaveShadeOpenOnKeyguardHide() =
302 testScope.runTest {
303 whenever(lockScreenUserManager.shouldShowLockscreenNotifications()).thenReturn(false)
304 whenever(lockScreenUserManager.isLockscreenPublicMode(any())).thenReturn(true)
305 transitionController.goToLockedShade(null)
306 val captor = argumentCaptor<Runnable>()
307 verify(centralSurfaces)
308 .showBouncerWithDimissAndCancelIfKeyguard(isNull(), captor.capture())
309 captor.value.run()
310 verify(statusbarStateController).setLeaveOpenOnKeyguardHide(false)
311 }
312
313 @Test
testDragDownAmountDoesntCallOutInLockedDownShadenull314 fun testDragDownAmountDoesntCallOutInLockedDownShade() =
315 testScope.runTest {
316 whenever(nsslController.isInLockedDownShade).thenReturn(true)
317 transitionController.dragDownAmount = 10f
318 verify(nsslController, never()).setTransitionToFullShadeAmount(anyFloat())
319 verify(mediaHierarchyManager, never()).setTransitionToFullShadeAmount(anyFloat())
320 verify(scrimController, never())
321 .setTransitionToFullShadeProgress(anyFloat(), anyFloat())
322 verify(transitionControllerCallback, never())
323 .setTransitionToFullShadeAmount(anyFloat(), anyBoolean(), anyLong())
324 verify(qsTransitionController, never()).dragDownAmount = anyFloat()
325 }
326
327 @Test
testDragDownAmountCallsOutnull328 fun testDragDownAmountCallsOut() =
329 testScope.runTest {
330 transitionController.dragDownAmount = 10f
331 verify(nsslController).setTransitionToFullShadeAmount(anyFloat())
332 verify(mediaHierarchyManager).setTransitionToFullShadeAmount(anyFloat())
333 verify(scrimController).setTransitionToFullShadeProgress(anyFloat(), anyFloat())
334 verify(transitionControllerCallback)
335 .setTransitionToFullShadeAmount(anyFloat(), anyBoolean(), anyLong())
336 verify(qsTransitionController).dragDownAmount = 10f
337 verify(depthController).transitionToFullShadeProgress = anyFloat()
338 }
339
340 @Test
testDragDownAmount_depthDistanceIsZero_setsProgressToZeronull341 fun testDragDownAmount_depthDistanceIsZero_setsProgressToZero() =
342 testScope.runTest {
343 context
344 .getOrCreateTestableResources()
345 .addOverride(R.dimen.lockscreen_shade_depth_controller_transition_distance, 0)
346 configurationController.notifyConfigurationChanged()
347
348 transitionController.dragDownAmount = 10f
349
350 verify(depthController).transitionToFullShadeProgress = 0f
351 }
352
353 @Test
testDragDownAmount_depthDistanceNonZero_setsProgressBasedOnDistancenull354 fun testDragDownAmount_depthDistanceNonZero_setsProgressBasedOnDistance() =
355 testScope.runTest {
356 context
357 .getOrCreateTestableResources()
358 .addOverride(R.dimen.lockscreen_shade_depth_controller_transition_distance, 100)
359 configurationController.notifyConfigurationChanged()
360
361 transitionController.dragDownAmount = 10f
362
363 verify(depthController).transitionToFullShadeProgress = 0.1f
364 }
365
366 @Test
setDragAmount_setsKeyguardTransitionProgressnull367 fun setDragAmount_setsKeyguardTransitionProgress() =
368 testScope.runTest {
369 transitionController.dragDownAmount = 10f
370
371 verify(shadeLockscreenInteractor).setKeyguardTransitionProgress(anyFloat(), anyInt())
372 }
373
374 @Test
setDragAmount_setsKeyguardAlphaBasedOnDistancenull375 fun setDragAmount_setsKeyguardAlphaBasedOnDistance() =
376 testScope.runTest {
377 val alphaDistance =
378 context.resources.getDimensionPixelSize(
379 R.dimen.lockscreen_shade_npvc_keyguard_content_alpha_transition_distance
380 )
381 transitionController.dragDownAmount = 10f
382
383 val expectedAlpha = 1 - 10f / alphaDistance
384 verify(shadeLockscreenInteractor)
385 .setKeyguardTransitionProgress(eq(expectedAlpha), anyInt())
386 }
387
388 @Test
setDragAmount_notInSplitShade_setsKeyguardTranslationToZeronull389 fun setDragAmount_notInSplitShade_setsKeyguardTranslationToZero() =
390 testScope.runTest {
391 val mediaTranslationY = 123
392 disableSplitShade()
393 whenever(mediaHierarchyManager.isCurrentlyInGuidedTransformation()).thenReturn(true)
394 whenever(mediaHierarchyManager.getGuidedTransformationTranslationY())
395 .thenReturn(mediaTranslationY)
396
397 transitionController.dragDownAmount = 10f
398
399 verify(shadeLockscreenInteractor).setKeyguardTransitionProgress(anyFloat(), eq(0))
400 }
401
402 @Test
setDragAmount_inSplitShade_setsKeyguardTranslationBasedOnMediaTranslationnull403 fun setDragAmount_inSplitShade_setsKeyguardTranslationBasedOnMediaTranslation() =
404 testScope.runTest {
405 val mediaTranslationY = 123
406 enableSplitShade()
407 whenever(mediaHierarchyManager.isCurrentlyInGuidedTransformation()).thenReturn(true)
408 whenever(mediaHierarchyManager.getGuidedTransformationTranslationY())
409 .thenReturn(mediaTranslationY)
410
411 transitionController.dragDownAmount = 10f
412
413 verify(shadeLockscreenInteractor)
414 .setKeyguardTransitionProgress(anyFloat(), eq(mediaTranslationY))
415 }
416
417 @Test
setDragAmount_inSplitShade_mediaNotShowing_setsKeyguardTranslationBasedOnDistancenull418 fun setDragAmount_inSplitShade_mediaNotShowing_setsKeyguardTranslationBasedOnDistance() =
419 testScope.runTest {
420 enableSplitShade()
421 whenever(mediaHierarchyManager.isCurrentlyInGuidedTransformation()).thenReturn(false)
422 whenever(mediaHierarchyManager.getGuidedTransformationTranslationY()).thenReturn(123)
423
424 transitionController.dragDownAmount = 10f
425
426 val distance =
427 context.resources.getDimensionPixelSize(
428 R.dimen.lockscreen_shade_keyguard_transition_distance
429 )
430 val offset =
431 context.resources.getDimensionPixelSize(
432 R.dimen.lockscreen_shade_keyguard_transition_vertical_offset
433 )
434 val expectedTranslation = 10f / distance * offset
435 verify(shadeLockscreenInteractor)
436 .setKeyguardTransitionProgress(anyFloat(), eq(expectedTranslation.toInt()))
437 }
438
439 @Test
setDragDownAmount_setsValueOnMediaHierarchyManagernull440 fun setDragDownAmount_setsValueOnMediaHierarchyManager() =
441 testScope.runTest {
442 transitionController.dragDownAmount = 10f
443
444 verify(mediaHierarchyManager).setTransitionToFullShadeAmount(10f)
445 }
446
447 @Test
setDragAmount_setsScrimProgressBasedOnScrimDistancenull448 fun setDragAmount_setsScrimProgressBasedOnScrimDistance() =
449 testScope.runTest {
450 val distance = 10
451 context.orCreateTestableResources.addOverride(
452 R.dimen.lockscreen_shade_scrim_transition_distance,
453 distance,
454 )
455 configurationController.notifyConfigurationChanged()
456
457 transitionController.dragDownAmount = 5f
458
459 verify(scrimController)
460 .transitionToFullShadeProgress(
461 progress = eq(0.5f),
462 lockScreenNotificationsProgress = anyFloat(),
463 )
464 }
465
466 @Test
setDragAmount_setsNotificationsScrimProgressBasedOnNotificationsScrimDistanceAndDelaynull467 fun setDragAmount_setsNotificationsScrimProgressBasedOnNotificationsScrimDistanceAndDelay() =
468 testScope.runTest {
469 val distance = 100
470 val delay = 10
471 context.orCreateTestableResources.addOverride(
472 R.dimen.lockscreen_shade_notifications_scrim_transition_distance,
473 distance,
474 )
475 context.orCreateTestableResources.addOverride(
476 R.dimen.lockscreen_shade_notifications_scrim_transition_delay,
477 delay,
478 )
479 configurationController.notifyConfigurationChanged()
480
481 transitionController.dragDownAmount = 20f
482
483 verify(scrimController)
484 .transitionToFullShadeProgress(
485 progress = anyFloat(),
486 lockScreenNotificationsProgress = eq(0.1f),
487 )
488 }
489
490 @Test
setDragAmount_dragAmountLessThanNotifDelayDistance_setsNotificationsScrimProgressToZeronull491 fun setDragAmount_dragAmountLessThanNotifDelayDistance_setsNotificationsScrimProgressToZero() =
492 testScope.runTest {
493 val distance = 100
494 val delay = 50
495 context.orCreateTestableResources.addOverride(
496 R.dimen.lockscreen_shade_notifications_scrim_transition_distance,
497 distance,
498 )
499 context.orCreateTestableResources.addOverride(
500 R.dimen.lockscreen_shade_notifications_scrim_transition_delay,
501 delay,
502 )
503 configurationController.notifyConfigurationChanged()
504
505 transitionController.dragDownAmount = 20f
506
507 verify(scrimController)
508 .transitionToFullShadeProgress(
509 progress = anyFloat(),
510 lockScreenNotificationsProgress = eq(0f),
511 )
512 }
513
514 @Test
setDragAmount_dragAmountMoreThanTotalDistance_setsNotificationsScrimProgressToOnenull515 fun setDragAmount_dragAmountMoreThanTotalDistance_setsNotificationsScrimProgressToOne() =
516 testScope.runTest {
517 val distance = 100
518 val delay = 50
519 context.orCreateTestableResources.addOverride(
520 R.dimen.lockscreen_shade_notifications_scrim_transition_distance,
521 distance,
522 )
523 context.orCreateTestableResources.addOverride(
524 R.dimen.lockscreen_shade_notifications_scrim_transition_delay,
525 delay,
526 )
527 configurationController.notifyConfigurationChanged()
528
529 transitionController.dragDownAmount = 999999f
530
531 verify(scrimController)
532 .transitionToFullShadeProgress(
533 progress = anyFloat(),
534 lockScreenNotificationsProgress = eq(1f),
535 )
536 }
537
538 @Test
setDragDownAmount_inSplitShade_setsValueOnMediaHierarchyManagernull539 fun setDragDownAmount_inSplitShade_setsValueOnMediaHierarchyManager() =
540 testScope.runTest {
541 enableSplitShade()
542
543 transitionController.dragDownAmount = 10f
544
545 verify(mediaHierarchyManager).setTransitionToFullShadeAmount(10f)
546 }
547
548 @Test
setDragAmount_notInSplitShade_forwardsToSingleShadeOverScrollernull549 fun setDragAmount_notInSplitShade_forwardsToSingleShadeOverScroller() =
550 testScope.runTest {
551 disableSplitShade()
552
553 transitionController.dragDownAmount = 10f
554
555 verify(singleShadeOverScroller).expansionDragDownAmount = 10f
556 verifyNoMoreInteractions(splitShadeOverScroller)
557 }
558
559 @Test
setDragAmount_inSplitShade_forwardsToSplitShadeOverScrollernull560 fun setDragAmount_inSplitShade_forwardsToSplitShadeOverScroller() =
561 testScope.runTest {
562 enableSplitShade()
563
564 transitionController.dragDownAmount = 10f
565
566 verify(splitShadeOverScroller).expansionDragDownAmount = 10f
567 verifyNoMoreInteractions(singleShadeOverScroller)
568 }
569
570 @Test
setDragDownAmount_inSplitShade_setsKeyguardStatusBarAlphaBasedOnDistancenull571 fun setDragDownAmount_inSplitShade_setsKeyguardStatusBarAlphaBasedOnDistance() =
572 testScope.runTest {
573 val alphaDistance =
574 context.resources.getDimensionPixelSize(
575 R.dimen.lockscreen_shade_npvc_keyguard_content_alpha_transition_distance
576 )
577 val dragDownAmount = 10f
578 enableSplitShade()
579
580 transitionController.dragDownAmount = dragDownAmount
581
582 val expectedAlpha = 1 - dragDownAmount / alphaDistance
583 verify(shadeLockscreenInteractor).setKeyguardStatusBarAlpha(expectedAlpha)
584 }
585
586 @Test
setDragDownAmount_notInSplitShade_setsKeyguardStatusBarAlphaToMinusOnenull587 fun setDragDownAmount_notInSplitShade_setsKeyguardStatusBarAlphaToMinusOne() =
588 testScope.runTest {
589 disableSplitShade()
590
591 transitionController.dragDownAmount = 10f
592
593 verify(shadeLockscreenInteractor).setKeyguardStatusBarAlpha(-1f)
594 }
595
596 @Test
nullQs_canDragDownFromAdapternull597 fun nullQs_canDragDownFromAdapter() =
598 testScope.runTest {
599 transitionController.qS = null
600
601 qsSceneAdapter.isQsFullyCollapsed = true
602 assertTrue("Can't drag down on keyguard", transitionController.canDragDown())
603 qsSceneAdapter.isQsFullyCollapsed = false
604 assertFalse("Can drag down when QS is expanded", transitionController.canDragDown())
605 }
606
enableSplitShadenull607 private fun enableSplitShade() {
608 setSplitShadeEnabled(true)
609 }
610
disableSplitShadenull611 private fun disableSplitShade() {
612 setSplitShadeEnabled(false)
613 }
614
setSplitShadeEnablednull615 private fun setSplitShadeEnabled(enabled: Boolean) {
616 overrideResource(R.bool.config_use_split_notification_shade, enabled)
617 configurationController.notifyConfigurationChanged()
618 }
619
620 /**
621 * Wrapper around [ScrimController.transitionToFullShadeProgress] that has named parameters for
622 * clarify and easier refactoring of parameter names.
623 */
transitionToFullShadeProgressnull624 private fun ScrimController.transitionToFullShadeProgress(
625 progress: Float,
626 lockScreenNotificationsProgress: Float,
627 ) {
628 setTransitionToFullShadeProgress(progress, lockScreenNotificationsProgress)
629 }
630 }
631