Loading packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt +9 −5 Original line number Original line Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.systemui.media import android.view.View import android.view.View import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.NotificationLockscreenUserManager import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.SysuiStatusBarStateController import com.android.systemui.statusbar.SysuiStatusBarStateController import com.android.systemui.statusbar.notification.stack.MediaHeaderView import com.android.systemui.statusbar.notification.stack.MediaHeaderView Loading @@ -33,7 +34,8 @@ import javax.inject.Singleton class KeyguardMediaController @Inject constructor( class KeyguardMediaController @Inject constructor( private val mediaHost: MediaHost, private val mediaHost: MediaHost, private val bypassController: KeyguardBypassController, private val bypassController: KeyguardBypassController, private val statusBarStateController: SysuiStatusBarStateController private val statusBarStateController: SysuiStatusBarStateController, private val notifLockscreenUserManager: NotificationLockscreenUserManager ) { ) { init { init { Loading Loading @@ -61,10 +63,12 @@ class KeyguardMediaController @Inject constructor( } } private fun updateVisibility() { private fun updateVisibility() { val shouldBeVisible = mediaHost.visible val keyguardOrUserSwitcher = (statusBarStateController.state == StatusBarState.KEYGUARD || && !bypassController.bypassEnabled && (statusBarStateController.state == StatusBarState.KEYGUARD || statusBarStateController.state == StatusBarState.FULLSCREEN_USER_SWITCHER) statusBarStateController.state == StatusBarState.FULLSCREEN_USER_SWITCHER) val shouldBeVisible = mediaHost.visible && !bypassController.bypassEnabled && keyguardOrUserSwitcher && notifLockscreenUserManager.shouldShowLockscreenNotifications() view?.visibility = if (shouldBeVisible) View.VISIBLE else View.GONE view?.visibility = if (shouldBeVisible) View.VISIBLE else View.GONE } } } } No newline at end of file packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt +26 −24 Original line number Original line Diff line number Diff line Loading @@ -26,6 +26,7 @@ import android.view.ViewGroup import android.view.ViewGroupOverlay import android.view.ViewGroupOverlay import com.android.systemui.Interpolators import com.android.systemui.Interpolators import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.NotificationLockscreenUserManager import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.SysuiStatusBarStateController import com.android.systemui.statusbar.SysuiStatusBarStateController import com.android.systemui.statusbar.notification.stack.StackStateAnimator import com.android.systemui.statusbar.notification.stack.StackStateAnimator Loading @@ -46,7 +47,8 @@ class MediaHierarchyManager @Inject constructor( private val keyguardStateController: KeyguardStateController, private val keyguardStateController: KeyguardStateController, private val bypassController: KeyguardBypassController, private val bypassController: KeyguardBypassController, private val mediaViewManager: MediaViewManager, private val mediaViewManager: MediaViewManager, private val mediaMeasurementProvider: MediaMeasurementManager private val mediaMeasurementProvider: MediaMeasurementManager, private val notifLockscreenUserManager: NotificationLockscreenUserManager ) { ) { /** /** * The root overlay of the hierarchy. This is where the media notification is attached to * The root overlay of the hierarchy. This is where the media notification is attached to Loading Loading @@ -138,7 +140,7 @@ class MediaHierarchyManager @Inject constructor( */ */ fun register(mediaObject: MediaHost): ViewGroup { fun register(mediaObject: MediaHost): ViewGroup { val viewHost = createUniqueObjectHost(mediaObject) val viewHost = createUniqueObjectHost(mediaObject) mediaObject.hostView = viewHost; mediaObject.hostView = viewHost mediaHosts[mediaObject.location] = mediaObject mediaHosts[mediaObject.location] = mediaObject if (mediaObject.location == desiredLocation) { if (mediaObject.location == desiredLocation) { // In case we are overriding a view that is already visible, make sure we attach it // In case we are overriding a view that is already visible, make sure we attach it Loading Loading @@ -215,8 +217,8 @@ class MediaHierarchyManager @Inject constructor( applyTargetStateIfNotAnimating() applyTargetStateIfNotAnimating() } else if (animate) { } else if (animate) { animator.cancel() animator.cancel() if (currentAttachmentLocation == IN_OVERLAY if (currentAttachmentLocation == IN_OVERLAY || || !previousHost.hostView.isAttachedToWindow) { !previousHost.hostView.isAttachedToWindow) { // Let's animate to the new position, starting from the current position // Let's animate to the new position, starting from the current position // We also go in here in case the view was detached, since the bounds wouldn't // We also go in here in case the view was detached, since the bounds wouldn't // be correct anymore // be correct anymore Loading @@ -237,10 +239,10 @@ class MediaHierarchyManager @Inject constructor( @MediaLocation currentLocation: Int, @MediaLocation currentLocation: Int, @MediaLocation previousLocation: Int @MediaLocation previousLocation: Int ): Boolean { ): Boolean { if (currentLocation == LOCATION_QQS if (currentLocation == LOCATION_QQS && && previousLocation == LOCATION_LOCKSCREEN previousLocation == LOCATION_LOCKSCREEN && && (statusBarStateController.leaveOpenOnKeyguardHide() (statusBarStateController.leaveOpenOnKeyguardHide() || || statusbarState == StatusBarState.SHADE_LOCKED)) { statusbarState == StatusBarState.SHADE_LOCKED)) { // Usually listening to the isShown is enough to determine this, but there is some // Usually listening to the isShown is enough to determine this, but there is some // non-trivial reattaching logic happening that will make the view not-shown earlier // non-trivial reattaching logic happening that will make the view not-shown earlier return true return true Loading @@ -254,7 +256,6 @@ class MediaHierarchyManager @Inject constructor( duration = animDuration duration = animDuration startDelay = delay startDelay = delay } } } } private fun getAnimationParams(previousLocation: Int, desiredLocation: Int): Pair<Long, Long> { private fun getAnimationParams(previousLocation: Int, desiredLocation: Int): Pair<Long, Long> { Loading @@ -262,8 +263,8 @@ class MediaHierarchyManager @Inject constructor( var delay = 0L var delay = 0L if (previousLocation == LOCATION_LOCKSCREEN && desiredLocation == LOCATION_QQS) { if (previousLocation == LOCATION_LOCKSCREEN && desiredLocation == LOCATION_QQS) { // Going to the full shade, let's adjust the animation duration // Going to the full shade, let's adjust the animation duration if (statusbarState == StatusBarState.SHADE if (statusbarState == StatusBarState.SHADE && && keyguardStateController.isKeyguardFadingAway) { keyguardStateController.isKeyguardFadingAway) { delay = keyguardStateController.keyguardFadingAwayDelay delay = keyguardStateController.keyguardFadingAwayDelay } } animDuration = StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE.toLong() animDuration = StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE.toLong() Loading Loading @@ -377,19 +378,20 @@ class MediaHierarchyManager @Inject constructor( } } private fun isTransitionRunning(): Boolean { private fun isTransitionRunning(): Boolean { return isCurrentlyInGuidedTransformation() && getTransformationProgress() != 1.0f return isCurrentlyInGuidedTransformation() && getTransformationProgress() != 1.0f || || animator.isRunning animator.isRunning } } @MediaLocation @MediaLocation private fun calculateLocation(): Int { private fun calculateLocation(): Int { val onLockscreen = (!bypassController.bypassEnabled val onLockscreen = (!bypassController.bypassEnabled && && (statusbarState == StatusBarState.KEYGUARD (statusbarState == StatusBarState.KEYGUARD || || statusbarState == StatusBarState.FULLSCREEN_USER_SWITCHER)) statusbarState == StatusBarState.FULLSCREEN_USER_SWITCHER)) val allowedOnLockscreen = notifLockscreenUserManager.shouldShowLockscreenNotifications() return when { return when { qsExpansion > 0.0f && !onLockscreen -> LOCATION_QS qsExpansion > 0.0f && !onLockscreen -> LOCATION_QS qsExpansion > 0.4f && onLockscreen -> LOCATION_QS qsExpansion > 0.4f && onLockscreen -> LOCATION_QS onLockscreen -> LOCATION_LOCKSCREEN onLockscreen && allowedOnLockscreen -> LOCATION_LOCKSCREEN else -> LOCATION_QQS else -> LOCATION_QQS } } } } Loading packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt 0 → 100644 +100 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.media import android.testing.AndroidTestingRunner import android.view.View.GONE import android.view.View.VISIBLE import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.controls.controller.ControlsControllerImplTest.Companion.eq import com.android.systemui.statusbar.NotificationLockscreenUserManager import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.SysuiStatusBarStateController import com.android.systemui.statusbar.notification.stack.MediaHeaderView import com.android.systemui.statusbar.phone.KeyguardBypassController import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.Captor import org.mockito.Mock import org.mockito.Mockito.`when` import org.mockito.Mockito.verify import org.mockito.junit.MockitoJUnit @SmallTest @RunWith(AndroidTestingRunner::class) class KeyguardMediaControllerTest : SysuiTestCase() { @Mock private lateinit var mediaHost: MediaHost @Mock private lateinit var bypassController: KeyguardBypassController @Mock private lateinit var statusBarStateController: SysuiStatusBarStateController @Mock private lateinit var notificationLockscreenUserManager: NotificationLockscreenUserManager @Mock private lateinit var mediaHeaderView: MediaHeaderView @Captor private lateinit var visibilityListener: ArgumentCaptor<((Boolean) -> Unit)> @JvmField @Rule val mockito = MockitoJUnit.rule() private lateinit var keyguardMediaController: KeyguardMediaController @Before fun setup() { keyguardMediaController = KeyguardMediaController(mediaHost, bypassController, statusBarStateController, notificationLockscreenUserManager) } @Test fun testAttach_hiddenWhenHostIsHidden() { `when`(mediaHost.visible).thenReturn(false) triggerVisibilityListener() verify(mediaHeaderView).visibility = eq(GONE) } @Test fun testAttach_visibleOnKeyguard() { `when`(mediaHost.visible).thenReturn(true) `when`(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD) `when`(notificationLockscreenUserManager.shouldShowLockscreenNotifications()) .thenReturn(true) triggerVisibilityListener() verify(mediaHeaderView).visibility = eq(VISIBLE) } @Test fun testAttach_hiddenOnKeyguard_whenNotificationsAreHidden() { `when`(mediaHost.visible).thenReturn(true) `when`(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD) `when`(notificationLockscreenUserManager.shouldShowLockscreenNotifications()) .thenReturn(false) triggerVisibilityListener() verify(mediaHeaderView).visibility = eq(GONE) } private fun triggerVisibilityListener() { keyguardMediaController.attach(mediaHeaderView) verify(mediaHost).visibleChangedListener = visibilityListener.capture() visibilityListener.value.invoke(true) } } No newline at end of file Loading
packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt +9 −5 Original line number Original line Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.systemui.media import android.view.View import android.view.View import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.NotificationLockscreenUserManager import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.SysuiStatusBarStateController import com.android.systemui.statusbar.SysuiStatusBarStateController import com.android.systemui.statusbar.notification.stack.MediaHeaderView import com.android.systemui.statusbar.notification.stack.MediaHeaderView Loading @@ -33,7 +34,8 @@ import javax.inject.Singleton class KeyguardMediaController @Inject constructor( class KeyguardMediaController @Inject constructor( private val mediaHost: MediaHost, private val mediaHost: MediaHost, private val bypassController: KeyguardBypassController, private val bypassController: KeyguardBypassController, private val statusBarStateController: SysuiStatusBarStateController private val statusBarStateController: SysuiStatusBarStateController, private val notifLockscreenUserManager: NotificationLockscreenUserManager ) { ) { init { init { Loading Loading @@ -61,10 +63,12 @@ class KeyguardMediaController @Inject constructor( } } private fun updateVisibility() { private fun updateVisibility() { val shouldBeVisible = mediaHost.visible val keyguardOrUserSwitcher = (statusBarStateController.state == StatusBarState.KEYGUARD || && !bypassController.bypassEnabled && (statusBarStateController.state == StatusBarState.KEYGUARD || statusBarStateController.state == StatusBarState.FULLSCREEN_USER_SWITCHER) statusBarStateController.state == StatusBarState.FULLSCREEN_USER_SWITCHER) val shouldBeVisible = mediaHost.visible && !bypassController.bypassEnabled && keyguardOrUserSwitcher && notifLockscreenUserManager.shouldShowLockscreenNotifications() view?.visibility = if (shouldBeVisible) View.VISIBLE else View.GONE view?.visibility = if (shouldBeVisible) View.VISIBLE else View.GONE } } } } No newline at end of file
packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt +26 −24 Original line number Original line Diff line number Diff line Loading @@ -26,6 +26,7 @@ import android.view.ViewGroup import android.view.ViewGroupOverlay import android.view.ViewGroupOverlay import com.android.systemui.Interpolators import com.android.systemui.Interpolators import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.NotificationLockscreenUserManager import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.SysuiStatusBarStateController import com.android.systemui.statusbar.SysuiStatusBarStateController import com.android.systemui.statusbar.notification.stack.StackStateAnimator import com.android.systemui.statusbar.notification.stack.StackStateAnimator Loading @@ -46,7 +47,8 @@ class MediaHierarchyManager @Inject constructor( private val keyguardStateController: KeyguardStateController, private val keyguardStateController: KeyguardStateController, private val bypassController: KeyguardBypassController, private val bypassController: KeyguardBypassController, private val mediaViewManager: MediaViewManager, private val mediaViewManager: MediaViewManager, private val mediaMeasurementProvider: MediaMeasurementManager private val mediaMeasurementProvider: MediaMeasurementManager, private val notifLockscreenUserManager: NotificationLockscreenUserManager ) { ) { /** /** * The root overlay of the hierarchy. This is where the media notification is attached to * The root overlay of the hierarchy. This is where the media notification is attached to Loading Loading @@ -138,7 +140,7 @@ class MediaHierarchyManager @Inject constructor( */ */ fun register(mediaObject: MediaHost): ViewGroup { fun register(mediaObject: MediaHost): ViewGroup { val viewHost = createUniqueObjectHost(mediaObject) val viewHost = createUniqueObjectHost(mediaObject) mediaObject.hostView = viewHost; mediaObject.hostView = viewHost mediaHosts[mediaObject.location] = mediaObject mediaHosts[mediaObject.location] = mediaObject if (mediaObject.location == desiredLocation) { if (mediaObject.location == desiredLocation) { // In case we are overriding a view that is already visible, make sure we attach it // In case we are overriding a view that is already visible, make sure we attach it Loading Loading @@ -215,8 +217,8 @@ class MediaHierarchyManager @Inject constructor( applyTargetStateIfNotAnimating() applyTargetStateIfNotAnimating() } else if (animate) { } else if (animate) { animator.cancel() animator.cancel() if (currentAttachmentLocation == IN_OVERLAY if (currentAttachmentLocation == IN_OVERLAY || || !previousHost.hostView.isAttachedToWindow) { !previousHost.hostView.isAttachedToWindow) { // Let's animate to the new position, starting from the current position // Let's animate to the new position, starting from the current position // We also go in here in case the view was detached, since the bounds wouldn't // We also go in here in case the view was detached, since the bounds wouldn't // be correct anymore // be correct anymore Loading @@ -237,10 +239,10 @@ class MediaHierarchyManager @Inject constructor( @MediaLocation currentLocation: Int, @MediaLocation currentLocation: Int, @MediaLocation previousLocation: Int @MediaLocation previousLocation: Int ): Boolean { ): Boolean { if (currentLocation == LOCATION_QQS if (currentLocation == LOCATION_QQS && && previousLocation == LOCATION_LOCKSCREEN previousLocation == LOCATION_LOCKSCREEN && && (statusBarStateController.leaveOpenOnKeyguardHide() (statusBarStateController.leaveOpenOnKeyguardHide() || || statusbarState == StatusBarState.SHADE_LOCKED)) { statusbarState == StatusBarState.SHADE_LOCKED)) { // Usually listening to the isShown is enough to determine this, but there is some // Usually listening to the isShown is enough to determine this, but there is some // non-trivial reattaching logic happening that will make the view not-shown earlier // non-trivial reattaching logic happening that will make the view not-shown earlier return true return true Loading @@ -254,7 +256,6 @@ class MediaHierarchyManager @Inject constructor( duration = animDuration duration = animDuration startDelay = delay startDelay = delay } } } } private fun getAnimationParams(previousLocation: Int, desiredLocation: Int): Pair<Long, Long> { private fun getAnimationParams(previousLocation: Int, desiredLocation: Int): Pair<Long, Long> { Loading @@ -262,8 +263,8 @@ class MediaHierarchyManager @Inject constructor( var delay = 0L var delay = 0L if (previousLocation == LOCATION_LOCKSCREEN && desiredLocation == LOCATION_QQS) { if (previousLocation == LOCATION_LOCKSCREEN && desiredLocation == LOCATION_QQS) { // Going to the full shade, let's adjust the animation duration // Going to the full shade, let's adjust the animation duration if (statusbarState == StatusBarState.SHADE if (statusbarState == StatusBarState.SHADE && && keyguardStateController.isKeyguardFadingAway) { keyguardStateController.isKeyguardFadingAway) { delay = keyguardStateController.keyguardFadingAwayDelay delay = keyguardStateController.keyguardFadingAwayDelay } } animDuration = StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE.toLong() animDuration = StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE.toLong() Loading Loading @@ -377,19 +378,20 @@ class MediaHierarchyManager @Inject constructor( } } private fun isTransitionRunning(): Boolean { private fun isTransitionRunning(): Boolean { return isCurrentlyInGuidedTransformation() && getTransformationProgress() != 1.0f return isCurrentlyInGuidedTransformation() && getTransformationProgress() != 1.0f || || animator.isRunning animator.isRunning } } @MediaLocation @MediaLocation private fun calculateLocation(): Int { private fun calculateLocation(): Int { val onLockscreen = (!bypassController.bypassEnabled val onLockscreen = (!bypassController.bypassEnabled && && (statusbarState == StatusBarState.KEYGUARD (statusbarState == StatusBarState.KEYGUARD || || statusbarState == StatusBarState.FULLSCREEN_USER_SWITCHER)) statusbarState == StatusBarState.FULLSCREEN_USER_SWITCHER)) val allowedOnLockscreen = notifLockscreenUserManager.shouldShowLockscreenNotifications() return when { return when { qsExpansion > 0.0f && !onLockscreen -> LOCATION_QS qsExpansion > 0.0f && !onLockscreen -> LOCATION_QS qsExpansion > 0.4f && onLockscreen -> LOCATION_QS qsExpansion > 0.4f && onLockscreen -> LOCATION_QS onLockscreen -> LOCATION_LOCKSCREEN onLockscreen && allowedOnLockscreen -> LOCATION_LOCKSCREEN else -> LOCATION_QQS else -> LOCATION_QQS } } } } Loading
packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt 0 → 100644 +100 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.media import android.testing.AndroidTestingRunner import android.view.View.GONE import android.view.View.VISIBLE import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.controls.controller.ControlsControllerImplTest.Companion.eq import com.android.systemui.statusbar.NotificationLockscreenUserManager import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.SysuiStatusBarStateController import com.android.systemui.statusbar.notification.stack.MediaHeaderView import com.android.systemui.statusbar.phone.KeyguardBypassController import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.Captor import org.mockito.Mock import org.mockito.Mockito.`when` import org.mockito.Mockito.verify import org.mockito.junit.MockitoJUnit @SmallTest @RunWith(AndroidTestingRunner::class) class KeyguardMediaControllerTest : SysuiTestCase() { @Mock private lateinit var mediaHost: MediaHost @Mock private lateinit var bypassController: KeyguardBypassController @Mock private lateinit var statusBarStateController: SysuiStatusBarStateController @Mock private lateinit var notificationLockscreenUserManager: NotificationLockscreenUserManager @Mock private lateinit var mediaHeaderView: MediaHeaderView @Captor private lateinit var visibilityListener: ArgumentCaptor<((Boolean) -> Unit)> @JvmField @Rule val mockito = MockitoJUnit.rule() private lateinit var keyguardMediaController: KeyguardMediaController @Before fun setup() { keyguardMediaController = KeyguardMediaController(mediaHost, bypassController, statusBarStateController, notificationLockscreenUserManager) } @Test fun testAttach_hiddenWhenHostIsHidden() { `when`(mediaHost.visible).thenReturn(false) triggerVisibilityListener() verify(mediaHeaderView).visibility = eq(GONE) } @Test fun testAttach_visibleOnKeyguard() { `when`(mediaHost.visible).thenReturn(true) `when`(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD) `when`(notificationLockscreenUserManager.shouldShowLockscreenNotifications()) .thenReturn(true) triggerVisibilityListener() verify(mediaHeaderView).visibility = eq(VISIBLE) } @Test fun testAttach_hiddenOnKeyguard_whenNotificationsAreHidden() { `when`(mediaHost.visible).thenReturn(true) `when`(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD) `when`(notificationLockscreenUserManager.shouldShowLockscreenNotifications()) .thenReturn(false) triggerVisibilityListener() verify(mediaHeaderView).visibility = eq(GONE) } private fun triggerVisibilityListener() { keyguardMediaController.attach(mediaHeaderView) verify(mediaHost).visibleChangedListener = visibilityListener.capture() visibilityListener.value.invoke(true) } } No newline at end of file