Loading packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt +4 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,10 @@ class KeyguardTransitionInteractor constructor( repository: KeyguardTransitionRepository, ) { /** (any)->GONE transition information */ val anyStateToGoneTransition: Flow<TransitionStep> = repository.transitions.filter { step -> step.to == KeyguardState.GONE } /** (any)->AOD transition information */ val anyStateToAodTransition: Flow<TransitionStep> = repository.transitions.filter { step -> step.to == KeyguardState.AOD } Loading packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt +7 −1 Original line number Diff line number Diff line Loading @@ -50,6 +50,7 @@ import android.text.TextUtils import android.util.Log import androidx.media.utils.MediaConstants import com.android.internal.logging.InstanceId import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.Dumpable import com.android.systemui.R import com.android.systemui.broadcast.BroadcastDispatcher Loading Loading @@ -177,6 +178,7 @@ class MediaDataManager( private val mediaFlags: MediaFlags, private val logger: MediaUiEventLogger, private val smartspaceManager: SmartspaceManager, private val keyguardUpdateMonitor: KeyguardUpdateMonitor, ) : Dumpable, BcSmartspaceDataPlugin.SmartspaceTargetListener { companion object { Loading Loading @@ -241,6 +243,7 @@ class MediaDataManager( mediaFlags: MediaFlags, logger: MediaUiEventLogger, smartspaceManager: SmartspaceManager, keyguardUpdateMonitor: KeyguardUpdateMonitor, ) : this( context, backgroundExecutor, Loading @@ -264,6 +267,7 @@ class MediaDataManager( mediaFlags, logger, smartspaceManager, keyguardUpdateMonitor, ) private val appChangeReceiver = Loading Loading @@ -1336,7 +1340,9 @@ class MediaDataManager( Assert.isMainThread() val removed = mediaEntries.remove(key) ?: return if (useMediaResumption && removed.resumeAction != null && removed.isLocalSession()) { if (keyguardUpdateMonitor.isUserInLockdown(removed.userId)) { logger.logMediaRemoved(removed.appUid, removed.packageName, removed.instanceId) } else if (useMediaResumption && removed.resumeAction != null && removed.isLocalSession()) { convertToResumePlayer(removed) } else if (mediaFlags.isRetainingPlayersEnabled()) { handlePossibleRemoval(removed, notificationRemoved = true) Loading packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt +48 −0 Original line number Diff line number Diff line Loading @@ -30,13 +30,20 @@ import android.view.ViewGroup import android.view.animation.PathInterpolator import android.widget.LinearLayout import androidx.annotation.VisibleForTesting import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle import com.android.internal.logging.InstanceId import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.KeyguardUpdateMonitorCallback import com.android.systemui.Dumpable import com.android.systemui.R import com.android.systemui.classifier.FalsingCollector import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dump.DumpManager import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.media.controls.models.player.MediaData import com.android.systemui.media.controls.models.player.MediaViewHolder import com.android.systemui.media.controls.models.recommendation.RecommendationViewHolder Loading @@ -63,6 +70,10 @@ import java.io.PrintWriter import java.util.TreeMap import javax.inject.Inject import javax.inject.Provider import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.flow.filter import kotlinx.coroutines.launch private const val TAG = "MediaCarouselController" private val settingsIntent = Intent().setAction(ACTION_MEDIA_CONTROLS_SETTINGS) Loading Loading @@ -91,6 +102,8 @@ constructor( private val logger: MediaUiEventLogger, private val debugLogger: MediaCarouselControllerLogger, private val mediaFlags: MediaFlags, private val keyguardUpdateMonitor: KeyguardUpdateMonitor, private val keyguardTransitionInteractor: KeyguardTransitionInteractor, ) : Dumpable { /** The current width of the carousel */ private var currentCarouselWidth: Int = 0 Loading Loading @@ -213,6 +226,17 @@ constructor( } } private val keyguardUpdateMonitorCallback = object : KeyguardUpdateMonitorCallback() { override fun onStrongAuthStateChanged(userId: Int) { if (keyguardUpdateMonitor.isUserInLockdown(userId)) { hideMediaCarousel() } else if (keyguardUpdateMonitor.isUserUnlocked(userId)) { showMediaCarousel() } } } /** * Update MediaCarouselScrollHandler.visibleToUser to reflect media card container visibility. * It will be called when the container is out of view. Loading Loading @@ -487,6 +511,13 @@ constructor( } } ) keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback) mediaCarousel.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.STARTED) { // A backup to show media carousel (if available) once the keyguard is gone. listenForAnyStateToGoneKeyguardTransition(this) } } } private fun inflateSettingsButton() { Loading Loading @@ -516,6 +547,23 @@ constructor( return mediaCarousel } private fun hideMediaCarousel() { mediaCarousel.visibility = View.GONE } private fun showMediaCarousel() { mediaCarousel.visibility = View.VISIBLE } @VisibleForTesting internal fun listenForAnyStateToGoneKeyguardTransition(scope: CoroutineScope): Job { return scope.launch { keyguardTransitionInteractor.anyStateToGoneTransition .filter { it.transitionState == TransitionState.FINISHED } .collect { showMediaCarousel() } } } private fun reorderAllPlayers( previousVisiblePlayerKey: MediaPlayerData.MediaSortKey?, key: String? = null Loading packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt +17 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import android.testing.TestableLooper.RunWithLooper import androidx.media.utils.MediaConstants import androidx.test.filters.SmallTest import com.android.internal.logging.InstanceId import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.InstanceIdSequenceFake import com.android.systemui.R import com.android.systemui.SysuiTestCase Loading Loading @@ -126,6 +127,7 @@ class MediaDataManagerTest : SysuiTestCase() { @Mock lateinit var pendingIntent: PendingIntent @Mock lateinit var activityStarter: ActivityStarter @Mock lateinit var smartspaceManager: SmartspaceManager @Mock lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor lateinit var smartspaceMediaDataProvider: SmartspaceMediaDataProvider @Mock lateinit var mediaSmartspaceTarget: SmartspaceTarget @Mock private lateinit var mediaRecommendationItem: SmartspaceAction Loading Loading @@ -187,6 +189,7 @@ class MediaDataManagerTest : SysuiTestCase() { mediaFlags = mediaFlags, logger = logger, smartspaceManager = smartspaceManager, keyguardUpdateMonitor = keyguardUpdateMonitor ) verify(tunerService) .addTunable(capture(tunableCaptor), eq(Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION)) Loading Loading @@ -242,6 +245,7 @@ class MediaDataManagerTest : SysuiTestCase() { whenever(mediaFlags.isRetainingPlayersEnabled()).thenReturn(false) whenever(mediaFlags.isPersistentSsCardEnabled()).thenReturn(false) whenever(logger.getNewInstanceId()).thenReturn(instanceIdSequence.newInstanceId()) whenever(keyguardUpdateMonitor.isUserInLockdown(any())).thenReturn(false) } @After Loading Loading @@ -682,6 +686,19 @@ class MediaDataManagerTest : SysuiTestCase() { verify(listener).onMediaDataRemoved(eq("0:$PACKAGE_NAME")) } fun testOnNotificationRemoved_lockDownMode() { whenever(keyguardUpdateMonitor.isUserInLockdown(any())).thenReturn(true) addNotificationAndLoad() val data = mediaDataCaptor.value mediaDataManager.onNotificationRemoved(KEY) verify(listener, never()).onMediaDataRemoved(eq(KEY)) verify(logger, never()) .logActiveConvertedToResume(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId)) verify(logger).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId)) } @Test fun testAddResumptionControls() { // WHEN resumption controls are added Loading packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt +56 −0 Original line number Diff line number Diff line Loading @@ -21,12 +21,20 @@ import android.content.res.Configuration import android.testing.AndroidTestingRunner import android.testing.TestableLooper import android.util.MathUtils.abs import android.view.View import androidx.test.filters.SmallTest import com.android.internal.logging.InstanceId import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.KeyguardUpdateMonitorCallback import com.android.systemui.SysuiTestCase import com.android.systemui.classifier.FalsingCollector import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dump.DumpManager import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.media.controls.MediaTestUtils import com.android.systemui.media.controls.models.player.MediaData import com.android.systemui.media.controls.models.recommendation.SmartspaceMediaData Loading @@ -49,6 +57,9 @@ import javax.inject.Provider import junit.framework.Assert.assertEquals import junit.framework.Assert.assertFalse import junit.framework.Assert.assertTrue import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Ignore import org.junit.Test Loading Loading @@ -90,11 +101,15 @@ class MediaCarouselControllerTest : SysuiTestCase() { @Mock lateinit var mediaCarousel: MediaScrollView @Mock lateinit var pageIndicator: PageIndicator @Mock lateinit var mediaFlags: MediaFlags @Mock lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor @Mock lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor private lateinit var transitionRepository: FakeKeyguardTransitionRepository @Captor lateinit var listener: ArgumentCaptor<MediaDataManager.Listener> @Captor lateinit var configListener: ArgumentCaptor<ConfigurationController.ConfigurationListener> @Captor lateinit var newConfig: ArgumentCaptor<Configuration> @Captor lateinit var visualStabilityCallback: ArgumentCaptor<OnReorderingAllowedListener> @Captor lateinit var keyguardCallback: ArgumentCaptor<KeyguardUpdateMonitorCallback> private val clock = FakeSystemClock() private lateinit var mediaCarouselController: MediaCarouselController Loading @@ -102,6 +117,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { @Before fun setup() { MockitoAnnotations.initMocks(this) transitionRepository = FakeKeyguardTransitionRepository() mediaCarouselController = MediaCarouselController( context, Loading @@ -119,11 +135,14 @@ class MediaCarouselControllerTest : SysuiTestCase() { logger, debugLogger, mediaFlags, keyguardUpdateMonitor, KeyguardTransitionInteractor(repository = transitionRepository), ) verify(configurationController).addCallback(capture(configListener)) verify(mediaDataManager).addListener(capture(listener)) verify(visualStabilityProvider) .addPersistentReorderingAllowedListener(capture(visualStabilityCallback)) verify(keyguardUpdateMonitor).registerCallback(capture(keyguardCallback)) whenever(mediaControlPanelFactory.get()).thenReturn(panel) whenever(panel.mediaViewController).thenReturn(mediaViewController) whenever(mediaDataManager.smartspaceMediaData).thenReturn(smartspaceMediaData) Loading Loading @@ -740,4 +759,41 @@ class MediaCarouselControllerTest : SysuiTestCase() { assertTrue(MediaPlayerData.visiblePlayerKeys().elementAt(0).isSsMediaRec) assertFalse(MediaPlayerData.visiblePlayerKeys().elementAt(0).data.active) } @Test fun testOnLockDownMode_hideMediaCarousel() { whenever(keyguardUpdateMonitor.isUserInLockdown(context.userId)).thenReturn(true) mediaCarouselController.mediaCarousel = mediaCarousel keyguardCallback.value.onStrongAuthStateChanged(context.userId) verify(mediaCarousel).visibility = View.GONE } @Test fun testLockDownModeOff_showMediaCarousel() { whenever(keyguardUpdateMonitor.isUserInLockdown(context.userId)).thenReturn(false) whenever(keyguardUpdateMonitor.isUserUnlocked(context.userId)).thenReturn(true) mediaCarouselController.mediaCarousel = mediaCarousel keyguardCallback.value.onStrongAuthStateChanged(context.userId) verify(mediaCarousel).visibility = View.VISIBLE } @ExperimentalCoroutinesApi @Test fun testKeyguardGone_showMediaCarousel() = runTest(UnconfinedTestDispatcher()) { mediaCarouselController.mediaCarousel = mediaCarousel val job = mediaCarouselController.listenForAnyStateToGoneKeyguardTransition(this) transitionRepository.sendTransitionStep( TransitionStep(to = KeyguardState.GONE, transitionState = TransitionState.FINISHED) ) verify(mediaCarousel).visibility = View.VISIBLE job.cancel() } } Loading
packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt +4 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,10 @@ class KeyguardTransitionInteractor constructor( repository: KeyguardTransitionRepository, ) { /** (any)->GONE transition information */ val anyStateToGoneTransition: Flow<TransitionStep> = repository.transitions.filter { step -> step.to == KeyguardState.GONE } /** (any)->AOD transition information */ val anyStateToAodTransition: Flow<TransitionStep> = repository.transitions.filter { step -> step.to == KeyguardState.AOD } Loading
packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt +7 −1 Original line number Diff line number Diff line Loading @@ -50,6 +50,7 @@ import android.text.TextUtils import android.util.Log import androidx.media.utils.MediaConstants import com.android.internal.logging.InstanceId import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.Dumpable import com.android.systemui.R import com.android.systemui.broadcast.BroadcastDispatcher Loading Loading @@ -177,6 +178,7 @@ class MediaDataManager( private val mediaFlags: MediaFlags, private val logger: MediaUiEventLogger, private val smartspaceManager: SmartspaceManager, private val keyguardUpdateMonitor: KeyguardUpdateMonitor, ) : Dumpable, BcSmartspaceDataPlugin.SmartspaceTargetListener { companion object { Loading Loading @@ -241,6 +243,7 @@ class MediaDataManager( mediaFlags: MediaFlags, logger: MediaUiEventLogger, smartspaceManager: SmartspaceManager, keyguardUpdateMonitor: KeyguardUpdateMonitor, ) : this( context, backgroundExecutor, Loading @@ -264,6 +267,7 @@ class MediaDataManager( mediaFlags, logger, smartspaceManager, keyguardUpdateMonitor, ) private val appChangeReceiver = Loading Loading @@ -1336,7 +1340,9 @@ class MediaDataManager( Assert.isMainThread() val removed = mediaEntries.remove(key) ?: return if (useMediaResumption && removed.resumeAction != null && removed.isLocalSession()) { if (keyguardUpdateMonitor.isUserInLockdown(removed.userId)) { logger.logMediaRemoved(removed.appUid, removed.packageName, removed.instanceId) } else if (useMediaResumption && removed.resumeAction != null && removed.isLocalSession()) { convertToResumePlayer(removed) } else if (mediaFlags.isRetainingPlayersEnabled()) { handlePossibleRemoval(removed, notificationRemoved = true) Loading
packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt +48 −0 Original line number Diff line number Diff line Loading @@ -30,13 +30,20 @@ import android.view.ViewGroup import android.view.animation.PathInterpolator import android.widget.LinearLayout import androidx.annotation.VisibleForTesting import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle import com.android.internal.logging.InstanceId import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.KeyguardUpdateMonitorCallback import com.android.systemui.Dumpable import com.android.systemui.R import com.android.systemui.classifier.FalsingCollector import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dump.DumpManager import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.media.controls.models.player.MediaData import com.android.systemui.media.controls.models.player.MediaViewHolder import com.android.systemui.media.controls.models.recommendation.RecommendationViewHolder Loading @@ -63,6 +70,10 @@ import java.io.PrintWriter import java.util.TreeMap import javax.inject.Inject import javax.inject.Provider import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.flow.filter import kotlinx.coroutines.launch private const val TAG = "MediaCarouselController" private val settingsIntent = Intent().setAction(ACTION_MEDIA_CONTROLS_SETTINGS) Loading Loading @@ -91,6 +102,8 @@ constructor( private val logger: MediaUiEventLogger, private val debugLogger: MediaCarouselControllerLogger, private val mediaFlags: MediaFlags, private val keyguardUpdateMonitor: KeyguardUpdateMonitor, private val keyguardTransitionInteractor: KeyguardTransitionInteractor, ) : Dumpable { /** The current width of the carousel */ private var currentCarouselWidth: Int = 0 Loading Loading @@ -213,6 +226,17 @@ constructor( } } private val keyguardUpdateMonitorCallback = object : KeyguardUpdateMonitorCallback() { override fun onStrongAuthStateChanged(userId: Int) { if (keyguardUpdateMonitor.isUserInLockdown(userId)) { hideMediaCarousel() } else if (keyguardUpdateMonitor.isUserUnlocked(userId)) { showMediaCarousel() } } } /** * Update MediaCarouselScrollHandler.visibleToUser to reflect media card container visibility. * It will be called when the container is out of view. Loading Loading @@ -487,6 +511,13 @@ constructor( } } ) keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback) mediaCarousel.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.STARTED) { // A backup to show media carousel (if available) once the keyguard is gone. listenForAnyStateToGoneKeyguardTransition(this) } } } private fun inflateSettingsButton() { Loading Loading @@ -516,6 +547,23 @@ constructor( return mediaCarousel } private fun hideMediaCarousel() { mediaCarousel.visibility = View.GONE } private fun showMediaCarousel() { mediaCarousel.visibility = View.VISIBLE } @VisibleForTesting internal fun listenForAnyStateToGoneKeyguardTransition(scope: CoroutineScope): Job { return scope.launch { keyguardTransitionInteractor.anyStateToGoneTransition .filter { it.transitionState == TransitionState.FINISHED } .collect { showMediaCarousel() } } } private fun reorderAllPlayers( previousVisiblePlayerKey: MediaPlayerData.MediaSortKey?, key: String? = null Loading
packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt +17 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import android.testing.TestableLooper.RunWithLooper import androidx.media.utils.MediaConstants import androidx.test.filters.SmallTest import com.android.internal.logging.InstanceId import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.InstanceIdSequenceFake import com.android.systemui.R import com.android.systemui.SysuiTestCase Loading Loading @@ -126,6 +127,7 @@ class MediaDataManagerTest : SysuiTestCase() { @Mock lateinit var pendingIntent: PendingIntent @Mock lateinit var activityStarter: ActivityStarter @Mock lateinit var smartspaceManager: SmartspaceManager @Mock lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor lateinit var smartspaceMediaDataProvider: SmartspaceMediaDataProvider @Mock lateinit var mediaSmartspaceTarget: SmartspaceTarget @Mock private lateinit var mediaRecommendationItem: SmartspaceAction Loading Loading @@ -187,6 +189,7 @@ class MediaDataManagerTest : SysuiTestCase() { mediaFlags = mediaFlags, logger = logger, smartspaceManager = smartspaceManager, keyguardUpdateMonitor = keyguardUpdateMonitor ) verify(tunerService) .addTunable(capture(tunableCaptor), eq(Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION)) Loading Loading @@ -242,6 +245,7 @@ class MediaDataManagerTest : SysuiTestCase() { whenever(mediaFlags.isRetainingPlayersEnabled()).thenReturn(false) whenever(mediaFlags.isPersistentSsCardEnabled()).thenReturn(false) whenever(logger.getNewInstanceId()).thenReturn(instanceIdSequence.newInstanceId()) whenever(keyguardUpdateMonitor.isUserInLockdown(any())).thenReturn(false) } @After Loading Loading @@ -682,6 +686,19 @@ class MediaDataManagerTest : SysuiTestCase() { verify(listener).onMediaDataRemoved(eq("0:$PACKAGE_NAME")) } fun testOnNotificationRemoved_lockDownMode() { whenever(keyguardUpdateMonitor.isUserInLockdown(any())).thenReturn(true) addNotificationAndLoad() val data = mediaDataCaptor.value mediaDataManager.onNotificationRemoved(KEY) verify(listener, never()).onMediaDataRemoved(eq(KEY)) verify(logger, never()) .logActiveConvertedToResume(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId)) verify(logger).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId)) } @Test fun testAddResumptionControls() { // WHEN resumption controls are added Loading
packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt +56 −0 Original line number Diff line number Diff line Loading @@ -21,12 +21,20 @@ import android.content.res.Configuration import android.testing.AndroidTestingRunner import android.testing.TestableLooper import android.util.MathUtils.abs import android.view.View import androidx.test.filters.SmallTest import com.android.internal.logging.InstanceId import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.KeyguardUpdateMonitorCallback import com.android.systemui.SysuiTestCase import com.android.systemui.classifier.FalsingCollector import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dump.DumpManager import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.media.controls.MediaTestUtils import com.android.systemui.media.controls.models.player.MediaData import com.android.systemui.media.controls.models.recommendation.SmartspaceMediaData Loading @@ -49,6 +57,9 @@ import javax.inject.Provider import junit.framework.Assert.assertEquals import junit.framework.Assert.assertFalse import junit.framework.Assert.assertTrue import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Ignore import org.junit.Test Loading Loading @@ -90,11 +101,15 @@ class MediaCarouselControllerTest : SysuiTestCase() { @Mock lateinit var mediaCarousel: MediaScrollView @Mock lateinit var pageIndicator: PageIndicator @Mock lateinit var mediaFlags: MediaFlags @Mock lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor @Mock lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor private lateinit var transitionRepository: FakeKeyguardTransitionRepository @Captor lateinit var listener: ArgumentCaptor<MediaDataManager.Listener> @Captor lateinit var configListener: ArgumentCaptor<ConfigurationController.ConfigurationListener> @Captor lateinit var newConfig: ArgumentCaptor<Configuration> @Captor lateinit var visualStabilityCallback: ArgumentCaptor<OnReorderingAllowedListener> @Captor lateinit var keyguardCallback: ArgumentCaptor<KeyguardUpdateMonitorCallback> private val clock = FakeSystemClock() private lateinit var mediaCarouselController: MediaCarouselController Loading @@ -102,6 +117,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { @Before fun setup() { MockitoAnnotations.initMocks(this) transitionRepository = FakeKeyguardTransitionRepository() mediaCarouselController = MediaCarouselController( context, Loading @@ -119,11 +135,14 @@ class MediaCarouselControllerTest : SysuiTestCase() { logger, debugLogger, mediaFlags, keyguardUpdateMonitor, KeyguardTransitionInteractor(repository = transitionRepository), ) verify(configurationController).addCallback(capture(configListener)) verify(mediaDataManager).addListener(capture(listener)) verify(visualStabilityProvider) .addPersistentReorderingAllowedListener(capture(visualStabilityCallback)) verify(keyguardUpdateMonitor).registerCallback(capture(keyguardCallback)) whenever(mediaControlPanelFactory.get()).thenReturn(panel) whenever(panel.mediaViewController).thenReturn(mediaViewController) whenever(mediaDataManager.smartspaceMediaData).thenReturn(smartspaceMediaData) Loading Loading @@ -740,4 +759,41 @@ class MediaCarouselControllerTest : SysuiTestCase() { assertTrue(MediaPlayerData.visiblePlayerKeys().elementAt(0).isSsMediaRec) assertFalse(MediaPlayerData.visiblePlayerKeys().elementAt(0).data.active) } @Test fun testOnLockDownMode_hideMediaCarousel() { whenever(keyguardUpdateMonitor.isUserInLockdown(context.userId)).thenReturn(true) mediaCarouselController.mediaCarousel = mediaCarousel keyguardCallback.value.onStrongAuthStateChanged(context.userId) verify(mediaCarousel).visibility = View.GONE } @Test fun testLockDownModeOff_showMediaCarousel() { whenever(keyguardUpdateMonitor.isUserInLockdown(context.userId)).thenReturn(false) whenever(keyguardUpdateMonitor.isUserUnlocked(context.userId)).thenReturn(true) mediaCarouselController.mediaCarousel = mediaCarousel keyguardCallback.value.onStrongAuthStateChanged(context.userId) verify(mediaCarousel).visibility = View.VISIBLE } @ExperimentalCoroutinesApi @Test fun testKeyguardGone_showMediaCarousel() = runTest(UnconfinedTestDispatcher()) { mediaCarouselController.mediaCarousel = mediaCarousel val job = mediaCarouselController.listenForAnyStateToGoneKeyguardTransition(this) transitionRepository.sendTransitionStep( TransitionStep(to = KeyguardState.GONE, transitionState = TransitionState.FINISHED) ) verify(mediaCarousel).visibility = View.VISIBLE job.cancel() } }