Loading packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaCarouselInteractorTest.kt +205 −3 Original line number Diff line number Diff line Loading @@ -16,34 +16,57 @@ package com.android.systemui.media.controls.domain.interactor import android.os.UserHandle import android.provider.Settings import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.compose.animation.scene.ObservableTransitionState import com.android.compose.animation.scene.SceneKey import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus import com.android.systemui.kosmos.testScope import com.android.systemui.kosmos.useUnconfinedTestDispatcher import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor import com.android.systemui.media.controls.domain.pipeline.interactor.mediaCarouselInteractor import com.android.systemui.media.controls.shared.model.MediaData import com.android.systemui.media.remedia.data.repository.MediaPipelineRepository import com.android.systemui.media.remedia.data.repository.mediaPipelineRepository import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.testKosmos import com.android.systemui.util.settings.fakeSettings import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(AndroidJUnit4::class) class MediaCarouselInteractorTest : SysuiTestCase() { private val kosmos = testKosmos() private val kosmos = testKosmos().useUnconfinedTestDispatcher() private val testScope = kosmos.testScope private val mediaPipelineRepository = kosmos.mediaPipelineRepository private val transitionRepository = kosmos.fakeKeyguardTransitionRepository private lateinit var mediaPipelineRepository: MediaPipelineRepository private val underTest: MediaCarouselInteractor = kosmos.mediaCarouselInteractor private lateinit var underTest: MediaCarouselInteractor @Before fun setUp() { mediaPipelineRepository = kosmos.mediaPipelineRepository underTest = kosmos.mediaCarouselInteractor underTest.start() } Loading Loading @@ -96,4 +119,183 @@ class MediaCarouselInteractorTest : SysuiTestCase() { @Test fun hasActiveMedia_noMediaSet_returnsFalse() = testScope.runTest { assertThat(underTest.hasActiveMedia()).isFalse() } @Test fun onLockscreen_mediaAllowed_lockedAndHidden_returnsFalse() = testScope.runTest { val isLockedAndHidden by collectLastValue(underTest.isLockedAndHidden) transitionRepository.sendTransitionSteps( from = KeyguardState.GONE, to = KeyguardState.LOCKSCREEN, this, ) assertThat(isLockedAndHidden).isFalse() } @Test fun onLockscreen_mediaNotAllowed_lockedAndHidden_returnsTrue() = testScope.runTest { val isLockedAndHidden by collectLastValue(underTest.isLockedAndHidden) kosmos.fakeSettings.putBoolForUser( Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, false, UserHandle.USER_CURRENT, ) transitionRepository.sendTransitionSteps( from = KeyguardState.GONE, to = KeyguardState.LOCKSCREEN, this, ) assertThat(isLockedAndHidden).isTrue() } @Test fun onKeyguardGone_mediaAllowed_lockedAndHidden_returnsFalse() = testScope.runTest { val isLockedAndHidden by collectLastValue(underTest.isLockedAndHidden) transitionRepository.sendTransitionSteps( from = KeyguardState.LOCKSCREEN, to = KeyguardState.GONE, this, ) assertThat(isLockedAndHidden).isFalse() } @Test fun onKeyguardGone_mediaNotAllowed_lockedAndHidden_returnsFalse() = testScope.runTest { val isLockedAndHidden by collectLastValue(underTest.isLockedAndHidden) kosmos.fakeSettings.putBoolForUser( Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, false, UserHandle.USER_CURRENT, ) transitionRepository.sendTransitionSteps( from = KeyguardState.LOCKSCREEN, to = KeyguardState.GONE, this, ) assertThat(isLockedAndHidden).isFalse() } @Test fun goingToDozing_mediaAllowed_lockedAndHidden_returnsFalse() = testScope.runTest { val isLockedAndHidden by collectLastValue(underTest.isLockedAndHidden) transitionRepository.sendTransitionSteps( from = KeyguardState.GONE, to = KeyguardState.DOZING, this, ) assertThat(isLockedAndHidden).isFalse() } @Test fun goingToDozing_mediaNotAllowed_lockedAndHidden_returnsTrue() = testScope.runTest { val isLockedAndHidden by collectLastValue(underTest.isLockedAndHidden) kosmos.fakeSettings.putBoolForUser( Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, false, UserHandle.USER_CURRENT, ) transitionRepository.sendTransitionSteps( from = KeyguardState.GONE, to = KeyguardState.DOZING, this, ) assertThat(isLockedAndHidden).isTrue() } @EnableSceneContainer @Test fun deviceNotEntered_mediaNotAllowed_lockedAndHidden() = testScope.runTest { val isLockedAndHidden by collectLastValue(underTest.isLockedAndHidden) kosmos.fakeSettings.putBoolForUser( Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, false, UserHandle.USER_CURRENT, ) setDeviceEntered(false) assertThat(isLockedAndHidden).isTrue() } @EnableSceneContainer @Test fun deviceNotEntered_mediaAllowed_notLockedAndHidden() = testScope.runTest { val isLockedAndHidden by collectLastValue(underTest.isLockedAndHidden) setDeviceEntered(false) assertThat(isLockedAndHidden).isFalse() } @EnableSceneContainer @Test fun deviceEntered_mediaNotAllowed_notLockedAndHidden() = testScope.runTest { val isLockedAndHidden by collectLastValue(underTest.isLockedAndHidden) kosmos.fakeSettings.putBoolForUser( Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, false, UserHandle.USER_CURRENT, ) setDeviceEntered(true) assertThat(isLockedAndHidden).isFalse() } @EnableSceneContainer @Test fun deviceEntered_mediaAllowed_notLockedAndHidden() = testScope.runTest { val isLockedAndHidden by collectLastValue(underTest.isLockedAndHidden) setDeviceEntered(true) assertThat(isLockedAndHidden).isFalse() } private fun TestScope.setDeviceEntered(isEntered: Boolean) { if (isEntered) { // Unlock the device, marking the device as entered kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus( SuccessFingerprintAuthenticationStatus(0, true) ) runCurrent() } setScene( if (isEntered) { Scenes.Gone } else { Scenes.Lockscreen } ) assertThat(kosmos.deviceEntryInteractor.isDeviceEntered.value).isEqualTo(isEntered) } private fun TestScope.setScene(key: SceneKey) { kosmos.sceneInteractor.changeScene(key, "test") kosmos.sceneInteractor.setTransitionState( MutableStateFlow<ObservableTransitionState>(ObservableTransitionState.Idle(key)) ) runCurrent() } } packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/controller/KeyguardMediaControllerTest.kt +75 −7 Original line number Diff line number Diff line Loading @@ -16,16 +16,29 @@ package com.android.systemui.media.controls.ui.controller import android.os.UserHandle import android.platform.test.annotations.EnableFlags import android.provider.Settings import android.testing.TestableLooper import android.view.View.GONE import android.view.View.VISIBLE import android.widget.FrameLayout import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.dump.DumpManager import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.kosmos.testScope import com.android.systemui.media.controls.domain.pipeline.interactor.mediaCarouselInteractor import com.android.systemui.media.controls.ui.view.MediaHost import com.android.systemui.media.controls.ui.view.MediaHostState import com.android.systemui.media.remedia.data.repository.setHasMedia import com.android.systemui.media.remedia.shared.flag.MediaControlsInComposeFlag import com.android.systemui.media.remedia.ui.viewmodel.factory.mediaViewModelFactory import com.android.systemui.media.remedia.ui.viewmodel.mediaFalsingSystem import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.SysuiStatusBarStateController Loading @@ -33,11 +46,14 @@ import com.android.systemui.statusbar.notification.stack.MediaContainerView import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController import com.android.systemui.testKosmos import com.android.systemui.util.animation.UniqueObjectHostView import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.android.systemui.util.settings.fakeSettings import com.google.common.truth.Truth.assertThat import junit.framework.Assert.assertTrue import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Rule import org.junit.Test Loading @@ -50,7 +66,7 @@ import org.mockito.junit.MockitoJUnit @SmallTest @RunWith(AndroidJUnit4::class) @TestableLooper.RunWithLooper @TestableLooper.RunWithLooper(setAsMainLooper = true) class KeyguardMediaControllerTest : SysuiTestCase() { @Mock private lateinit var mediaHost: MediaHost Loading @@ -60,6 +76,11 @@ class KeyguardMediaControllerTest : SysuiTestCase() { @JvmField @Rule val mockito = MockitoJUnit.rule() private val kosmos = testKosmos() private val testScope = kosmos.testScope private val mediaFalsingSystem = kosmos.mediaFalsingSystem private val mediaViewModelFactory = kosmos.mediaViewModelFactory private val transitionRepository = kosmos.fakeKeyguardTransitionRepository private val mediaContainerView: MediaContainerView = MediaContainerView(context, null) private val hostView = UniqueObjectHostView(context) private lateinit var keyguardMediaController: KeyguardMediaController Loading @@ -78,9 +99,15 @@ class KeyguardMediaControllerTest : SysuiTestCase() { whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD) whenever(mediaHost.hostView).thenReturn(hostView) hostView.layoutParams = FrameLayout.LayoutParams(100, 100) kosmos.fakeSettings.putBoolForUser( Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, true, UserHandle.USER_CURRENT, ) keyguardMediaController = KeyguardMediaController( mediaHost, kosmos.applicationCoroutineScope, bypassController, statusBarStateController, context, Loading @@ -88,20 +115,66 @@ class KeyguardMediaControllerTest : SysuiTestCase() { ResourcesSplitShadeStateController(), mock<KeyguardMediaControllerLogger>(), mock<DumpManager>(), mediaViewModelFactory, kosmos.mediaCarouselInteractor, mediaFalsingSystem, ) keyguardMediaController.attachSinglePaneContainer(mediaContainerView) keyguardMediaController.useSplitShade = false if (MediaControlsInComposeFlag.isEnabled) { kosmos.setHasMedia(visible = true, active = true) } else { verify(mediaHost).expansion = MediaHostState.EXPANDED } } @Test fun testHiddenWhenHostIsHidden() { if (MediaControlsInComposeFlag.isEnabled) { kosmos.setHasMedia(visible = false) } else { whenever(mediaHost.visible).thenReturn(false) } keyguardMediaController.refreshMediaPosition(TEST_REASON) assertThat(mediaContainerView.visibility).isEqualTo(GONE) } @EnableFlags(Flags.FLAG_MEDIA_CONTROLS_IN_COMPOSE) @Test fun mediaLockedAndHidden_mediaIsHidden() = testScope.runTest { kosmos.fakeSettings.putBoolForUser( Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, false, UserHandle.USER_CURRENT, ) transitionRepository.sendTransitionSteps( from = KeyguardState.GONE, to = KeyguardState.LOCKSCREEN, this, ) kosmos.setHasMedia(visible = true, active = true) assertThat(mediaContainerView.visibility).isEqualTo(GONE) } @EnableFlags(Flags.FLAG_MEDIA_CONTROLS_IN_COMPOSE) @Test fun mediaOnLockscreen_mediaIsVisible() = testScope.runTest { transitionRepository.sendTransitionSteps( from = KeyguardState.GONE, to = KeyguardState.LOCKSCREEN, this, ) kosmos.setHasMedia(visible = true, active = true) assertThat(mediaContainerView.visibility).isEqualTo(VISIBLE) } @Test fun testVisibleOnKeyguardOrFullScreenUserSwitcher() { testStateVisibility(StatusBarState.SHADE, GONE) Loading Loading @@ -156,11 +229,6 @@ class KeyguardMediaControllerTest : SysuiTestCase() { ) } @Test fun testMediaHost_expandedPlayer() { verify(mediaHost).expansion = MediaHostState.EXPANDED } @Test fun dozing_inSplitShade_mediaIsHidden() { val splitShadeContainer = FrameLayout(context) Loading packages/SystemUI/multivalentTests/src/com/android/systemui/media/remedia/data/repository/MediaRepositoryTest.kt +27 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ package com.android.systemui.media.remedia.data.repository import android.content.packageManager import android.media.session.MediaSession import android.os.UserHandle import android.provider.Settings import androidx.test.annotation.UiThreadTest import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest Loading @@ -30,6 +32,7 @@ import com.android.systemui.media.controls.shared.model.MediaData import com.android.systemui.media.remedia.data.model.MediaDataModel import com.android.systemui.res.R import com.android.systemui.testKosmos import com.android.systemui.util.settings.fakeSettings import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope Loading Loading @@ -263,6 +266,30 @@ class MediaRepositoryTest : SysuiTestCase() { .inOrder() } @Test fun toggleMediaControlsOnLockscreen() = testScope.runTest { val allowMediaOnLockscreen by collectLastValue(underTest.allowMediaPlayerOnLockscreen) assertThat(allowMediaOnLockscreen).isTrue() kosmos.fakeSettings.putBoolForUser( Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, value = false, UserHandle.USER_CURRENT, ) assertThat(allowMediaOnLockscreen).isFalse() kosmos.fakeSettings.putBoolForUser( Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, value = true, UserHandle.USER_CURRENT, ) assertThat(allowMediaOnLockscreen).isTrue() } private fun TestScope.addCurrentUserMediaEntry(data: MediaData) { underTest.addCurrentUserMediaEntry(data) runCurrent() Loading packages/SystemUI/src/com/android/systemui/media/controls/data/repository/MediaFilterRepository.kt +14 −1 Original line number Diff line number Diff line Loading @@ -20,15 +20,19 @@ import android.content.Context import com.android.internal.logging.InstanceId import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.media.controls.data.model.MediaSortKeyModel import com.android.systemui.media.controls.shared.model.MediaCommonModel import com.android.systemui.media.controls.shared.model.MediaData import com.android.systemui.media.controls.shared.model.MediaDataLoadingModel import com.android.systemui.media.remedia.data.model.UpdateArtInfoModel import com.android.systemui.media.remedia.data.repository.MediaPipelineRepository import com.android.systemui.util.settings.SecureSettings import com.android.systemui.util.time.SystemClock import java.util.TreeMap import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow Loading @@ -38,8 +42,17 @@ class MediaFilterRepository @Inject constructor( @Application private val applicationContext: Context, @Application applicationScope: CoroutineScope, @Background backgroundDispatcher: CoroutineDispatcher, private val systemClock: SystemClock, ) : MediaPipelineRepository(applicationContext) { secureSettings: SecureSettings, ) : MediaPipelineRepository( applicationContext, applicationScope, backgroundDispatcher, secureSettings, ) { private val _currentMedia: MutableStateFlow<List<MediaCommonModel>> = MutableStateFlow(mutableListOf()) Loading packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaCarouselInteractor.kt +32 −2 Original line number Diff line number Diff line Loading @@ -25,6 +25,11 @@ import com.android.internal.logging.InstanceId import com.android.systemui.CoreStartable import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.Edge import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING import com.android.systemui.keyguard.shared.model.KeyguardState.GONE import com.android.systemui.media.controls.data.repository.MediaFilterRepository import com.android.systemui.media.controls.domain.pipeline.MediaDataCombineLatest import com.android.systemui.media.controls.domain.pipeline.MediaDataFilterImpl Loading @@ -37,12 +42,15 @@ import com.android.systemui.media.controls.domain.resume.MediaResumeListener import com.android.systemui.media.remedia.data.repository.MediaPipelineRepository import com.android.systemui.media.remedia.shared.flag.MediaControlsInComposeFlag import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.scene.shared.model.Scenes import java.io.PrintWriter import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn Loading @@ -60,6 +68,8 @@ constructor( private val mediaDataCombineLatest: MediaDataCombineLatest, private val mediaDataFilter: MediaDataFilterImpl, private val mediaPipelineRepository: MediaPipelineRepository, keyguardTransitionInteractor: KeyguardTransitionInteractor, deviceEntryInteractor: DeviceEntryInteractor, ) : MediaDataManager, CoreStartable { /** Are there any media notifications active? */ Loading Loading @@ -91,6 +101,27 @@ constructor( MutableStateFlow(mutableListOf()) } val allowMediaOnLockscreen: StateFlow<Boolean> = mediaPipelineRepository.allowMediaPlayerOnLockscreen internal val isOnLockscreen: Flow<Boolean> = combine( @Suppress("DEPRECATION") keyguardTransitionInteractor.isFinishedIn(Scenes.Gone, GONE), keyguardTransitionInteractor.isInTransition(Edge.create(to = DOZING)), deviceEntryInteractor.isDeviceEntered, ) { isGone, isGoingToDozing, deviceEntered -> if (SceneContainerFlag.isEnabled) { !deviceEntered } else { !isGone || isGoingToDozing } } val isLockedAndHidden = combine(allowMediaOnLockscreen, isOnLockscreen) { allowMedia, onLockscreen -> !allowMedia && onLockscreen } override fun start() { if (!SceneContainerFlag.isEnabled && !MediaControlsInComposeFlag.isEnabled) { return Loading Loading @@ -212,8 +243,7 @@ constructor( val unsupported: Nothing get() = error( "Code path not supported when ${SceneContainerFlag.DESCRIPTION} or " + "media_controls_in_compose is enabled" "Code path not supported when ${SceneContainerFlag.DESCRIPTION} or media_controls_in_compose is enabled" ) } } Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaCarouselInteractorTest.kt +205 −3 Original line number Diff line number Diff line Loading @@ -16,34 +16,57 @@ package com.android.systemui.media.controls.domain.interactor import android.os.UserHandle import android.provider.Settings import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.compose.animation.scene.ObservableTransitionState import com.android.compose.animation.scene.SceneKey import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus import com.android.systemui.kosmos.testScope import com.android.systemui.kosmos.useUnconfinedTestDispatcher import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor import com.android.systemui.media.controls.domain.pipeline.interactor.mediaCarouselInteractor import com.android.systemui.media.controls.shared.model.MediaData import com.android.systemui.media.remedia.data.repository.MediaPipelineRepository import com.android.systemui.media.remedia.data.repository.mediaPipelineRepository import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.testKosmos import com.android.systemui.util.settings.fakeSettings import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(AndroidJUnit4::class) class MediaCarouselInteractorTest : SysuiTestCase() { private val kosmos = testKosmos() private val kosmos = testKosmos().useUnconfinedTestDispatcher() private val testScope = kosmos.testScope private val mediaPipelineRepository = kosmos.mediaPipelineRepository private val transitionRepository = kosmos.fakeKeyguardTransitionRepository private lateinit var mediaPipelineRepository: MediaPipelineRepository private val underTest: MediaCarouselInteractor = kosmos.mediaCarouselInteractor private lateinit var underTest: MediaCarouselInteractor @Before fun setUp() { mediaPipelineRepository = kosmos.mediaPipelineRepository underTest = kosmos.mediaCarouselInteractor underTest.start() } Loading Loading @@ -96,4 +119,183 @@ class MediaCarouselInteractorTest : SysuiTestCase() { @Test fun hasActiveMedia_noMediaSet_returnsFalse() = testScope.runTest { assertThat(underTest.hasActiveMedia()).isFalse() } @Test fun onLockscreen_mediaAllowed_lockedAndHidden_returnsFalse() = testScope.runTest { val isLockedAndHidden by collectLastValue(underTest.isLockedAndHidden) transitionRepository.sendTransitionSteps( from = KeyguardState.GONE, to = KeyguardState.LOCKSCREEN, this, ) assertThat(isLockedAndHidden).isFalse() } @Test fun onLockscreen_mediaNotAllowed_lockedAndHidden_returnsTrue() = testScope.runTest { val isLockedAndHidden by collectLastValue(underTest.isLockedAndHidden) kosmos.fakeSettings.putBoolForUser( Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, false, UserHandle.USER_CURRENT, ) transitionRepository.sendTransitionSteps( from = KeyguardState.GONE, to = KeyguardState.LOCKSCREEN, this, ) assertThat(isLockedAndHidden).isTrue() } @Test fun onKeyguardGone_mediaAllowed_lockedAndHidden_returnsFalse() = testScope.runTest { val isLockedAndHidden by collectLastValue(underTest.isLockedAndHidden) transitionRepository.sendTransitionSteps( from = KeyguardState.LOCKSCREEN, to = KeyguardState.GONE, this, ) assertThat(isLockedAndHidden).isFalse() } @Test fun onKeyguardGone_mediaNotAllowed_lockedAndHidden_returnsFalse() = testScope.runTest { val isLockedAndHidden by collectLastValue(underTest.isLockedAndHidden) kosmos.fakeSettings.putBoolForUser( Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, false, UserHandle.USER_CURRENT, ) transitionRepository.sendTransitionSteps( from = KeyguardState.LOCKSCREEN, to = KeyguardState.GONE, this, ) assertThat(isLockedAndHidden).isFalse() } @Test fun goingToDozing_mediaAllowed_lockedAndHidden_returnsFalse() = testScope.runTest { val isLockedAndHidden by collectLastValue(underTest.isLockedAndHidden) transitionRepository.sendTransitionSteps( from = KeyguardState.GONE, to = KeyguardState.DOZING, this, ) assertThat(isLockedAndHidden).isFalse() } @Test fun goingToDozing_mediaNotAllowed_lockedAndHidden_returnsTrue() = testScope.runTest { val isLockedAndHidden by collectLastValue(underTest.isLockedAndHidden) kosmos.fakeSettings.putBoolForUser( Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, false, UserHandle.USER_CURRENT, ) transitionRepository.sendTransitionSteps( from = KeyguardState.GONE, to = KeyguardState.DOZING, this, ) assertThat(isLockedAndHidden).isTrue() } @EnableSceneContainer @Test fun deviceNotEntered_mediaNotAllowed_lockedAndHidden() = testScope.runTest { val isLockedAndHidden by collectLastValue(underTest.isLockedAndHidden) kosmos.fakeSettings.putBoolForUser( Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, false, UserHandle.USER_CURRENT, ) setDeviceEntered(false) assertThat(isLockedAndHidden).isTrue() } @EnableSceneContainer @Test fun deviceNotEntered_mediaAllowed_notLockedAndHidden() = testScope.runTest { val isLockedAndHidden by collectLastValue(underTest.isLockedAndHidden) setDeviceEntered(false) assertThat(isLockedAndHidden).isFalse() } @EnableSceneContainer @Test fun deviceEntered_mediaNotAllowed_notLockedAndHidden() = testScope.runTest { val isLockedAndHidden by collectLastValue(underTest.isLockedAndHidden) kosmos.fakeSettings.putBoolForUser( Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, false, UserHandle.USER_CURRENT, ) setDeviceEntered(true) assertThat(isLockedAndHidden).isFalse() } @EnableSceneContainer @Test fun deviceEntered_mediaAllowed_notLockedAndHidden() = testScope.runTest { val isLockedAndHidden by collectLastValue(underTest.isLockedAndHidden) setDeviceEntered(true) assertThat(isLockedAndHidden).isFalse() } private fun TestScope.setDeviceEntered(isEntered: Boolean) { if (isEntered) { // Unlock the device, marking the device as entered kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus( SuccessFingerprintAuthenticationStatus(0, true) ) runCurrent() } setScene( if (isEntered) { Scenes.Gone } else { Scenes.Lockscreen } ) assertThat(kosmos.deviceEntryInteractor.isDeviceEntered.value).isEqualTo(isEntered) } private fun TestScope.setScene(key: SceneKey) { kosmos.sceneInteractor.changeScene(key, "test") kosmos.sceneInteractor.setTransitionState( MutableStateFlow<ObservableTransitionState>(ObservableTransitionState.Idle(key)) ) runCurrent() } }
packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/controller/KeyguardMediaControllerTest.kt +75 −7 Original line number Diff line number Diff line Loading @@ -16,16 +16,29 @@ package com.android.systemui.media.controls.ui.controller import android.os.UserHandle import android.platform.test.annotations.EnableFlags import android.provider.Settings import android.testing.TestableLooper import android.view.View.GONE import android.view.View.VISIBLE import android.widget.FrameLayout import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.dump.DumpManager import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.kosmos.testScope import com.android.systemui.media.controls.domain.pipeline.interactor.mediaCarouselInteractor import com.android.systemui.media.controls.ui.view.MediaHost import com.android.systemui.media.controls.ui.view.MediaHostState import com.android.systemui.media.remedia.data.repository.setHasMedia import com.android.systemui.media.remedia.shared.flag.MediaControlsInComposeFlag import com.android.systemui.media.remedia.ui.viewmodel.factory.mediaViewModelFactory import com.android.systemui.media.remedia.ui.viewmodel.mediaFalsingSystem import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.SysuiStatusBarStateController Loading @@ -33,11 +46,14 @@ import com.android.systemui.statusbar.notification.stack.MediaContainerView import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController import com.android.systemui.testKosmos import com.android.systemui.util.animation.UniqueObjectHostView import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.android.systemui.util.settings.fakeSettings import com.google.common.truth.Truth.assertThat import junit.framework.Assert.assertTrue import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Rule import org.junit.Test Loading @@ -50,7 +66,7 @@ import org.mockito.junit.MockitoJUnit @SmallTest @RunWith(AndroidJUnit4::class) @TestableLooper.RunWithLooper @TestableLooper.RunWithLooper(setAsMainLooper = true) class KeyguardMediaControllerTest : SysuiTestCase() { @Mock private lateinit var mediaHost: MediaHost Loading @@ -60,6 +76,11 @@ class KeyguardMediaControllerTest : SysuiTestCase() { @JvmField @Rule val mockito = MockitoJUnit.rule() private val kosmos = testKosmos() private val testScope = kosmos.testScope private val mediaFalsingSystem = kosmos.mediaFalsingSystem private val mediaViewModelFactory = kosmos.mediaViewModelFactory private val transitionRepository = kosmos.fakeKeyguardTransitionRepository private val mediaContainerView: MediaContainerView = MediaContainerView(context, null) private val hostView = UniqueObjectHostView(context) private lateinit var keyguardMediaController: KeyguardMediaController Loading @@ -78,9 +99,15 @@ class KeyguardMediaControllerTest : SysuiTestCase() { whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD) whenever(mediaHost.hostView).thenReturn(hostView) hostView.layoutParams = FrameLayout.LayoutParams(100, 100) kosmos.fakeSettings.putBoolForUser( Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, true, UserHandle.USER_CURRENT, ) keyguardMediaController = KeyguardMediaController( mediaHost, kosmos.applicationCoroutineScope, bypassController, statusBarStateController, context, Loading @@ -88,20 +115,66 @@ class KeyguardMediaControllerTest : SysuiTestCase() { ResourcesSplitShadeStateController(), mock<KeyguardMediaControllerLogger>(), mock<DumpManager>(), mediaViewModelFactory, kosmos.mediaCarouselInteractor, mediaFalsingSystem, ) keyguardMediaController.attachSinglePaneContainer(mediaContainerView) keyguardMediaController.useSplitShade = false if (MediaControlsInComposeFlag.isEnabled) { kosmos.setHasMedia(visible = true, active = true) } else { verify(mediaHost).expansion = MediaHostState.EXPANDED } } @Test fun testHiddenWhenHostIsHidden() { if (MediaControlsInComposeFlag.isEnabled) { kosmos.setHasMedia(visible = false) } else { whenever(mediaHost.visible).thenReturn(false) } keyguardMediaController.refreshMediaPosition(TEST_REASON) assertThat(mediaContainerView.visibility).isEqualTo(GONE) } @EnableFlags(Flags.FLAG_MEDIA_CONTROLS_IN_COMPOSE) @Test fun mediaLockedAndHidden_mediaIsHidden() = testScope.runTest { kosmos.fakeSettings.putBoolForUser( Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, false, UserHandle.USER_CURRENT, ) transitionRepository.sendTransitionSteps( from = KeyguardState.GONE, to = KeyguardState.LOCKSCREEN, this, ) kosmos.setHasMedia(visible = true, active = true) assertThat(mediaContainerView.visibility).isEqualTo(GONE) } @EnableFlags(Flags.FLAG_MEDIA_CONTROLS_IN_COMPOSE) @Test fun mediaOnLockscreen_mediaIsVisible() = testScope.runTest { transitionRepository.sendTransitionSteps( from = KeyguardState.GONE, to = KeyguardState.LOCKSCREEN, this, ) kosmos.setHasMedia(visible = true, active = true) assertThat(mediaContainerView.visibility).isEqualTo(VISIBLE) } @Test fun testVisibleOnKeyguardOrFullScreenUserSwitcher() { testStateVisibility(StatusBarState.SHADE, GONE) Loading Loading @@ -156,11 +229,6 @@ class KeyguardMediaControllerTest : SysuiTestCase() { ) } @Test fun testMediaHost_expandedPlayer() { verify(mediaHost).expansion = MediaHostState.EXPANDED } @Test fun dozing_inSplitShade_mediaIsHidden() { val splitShadeContainer = FrameLayout(context) Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/media/remedia/data/repository/MediaRepositoryTest.kt +27 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ package com.android.systemui.media.remedia.data.repository import android.content.packageManager import android.media.session.MediaSession import android.os.UserHandle import android.provider.Settings import androidx.test.annotation.UiThreadTest import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest Loading @@ -30,6 +32,7 @@ import com.android.systemui.media.controls.shared.model.MediaData import com.android.systemui.media.remedia.data.model.MediaDataModel import com.android.systemui.res.R import com.android.systemui.testKosmos import com.android.systemui.util.settings.fakeSettings import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope Loading Loading @@ -263,6 +266,30 @@ class MediaRepositoryTest : SysuiTestCase() { .inOrder() } @Test fun toggleMediaControlsOnLockscreen() = testScope.runTest { val allowMediaOnLockscreen by collectLastValue(underTest.allowMediaPlayerOnLockscreen) assertThat(allowMediaOnLockscreen).isTrue() kosmos.fakeSettings.putBoolForUser( Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, value = false, UserHandle.USER_CURRENT, ) assertThat(allowMediaOnLockscreen).isFalse() kosmos.fakeSettings.putBoolForUser( Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, value = true, UserHandle.USER_CURRENT, ) assertThat(allowMediaOnLockscreen).isTrue() } private fun TestScope.addCurrentUserMediaEntry(data: MediaData) { underTest.addCurrentUserMediaEntry(data) runCurrent() Loading
packages/SystemUI/src/com/android/systemui/media/controls/data/repository/MediaFilterRepository.kt +14 −1 Original line number Diff line number Diff line Loading @@ -20,15 +20,19 @@ import android.content.Context import com.android.internal.logging.InstanceId import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.media.controls.data.model.MediaSortKeyModel import com.android.systemui.media.controls.shared.model.MediaCommonModel import com.android.systemui.media.controls.shared.model.MediaData import com.android.systemui.media.controls.shared.model.MediaDataLoadingModel import com.android.systemui.media.remedia.data.model.UpdateArtInfoModel import com.android.systemui.media.remedia.data.repository.MediaPipelineRepository import com.android.systemui.util.settings.SecureSettings import com.android.systemui.util.time.SystemClock import java.util.TreeMap import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow Loading @@ -38,8 +42,17 @@ class MediaFilterRepository @Inject constructor( @Application private val applicationContext: Context, @Application applicationScope: CoroutineScope, @Background backgroundDispatcher: CoroutineDispatcher, private val systemClock: SystemClock, ) : MediaPipelineRepository(applicationContext) { secureSettings: SecureSettings, ) : MediaPipelineRepository( applicationContext, applicationScope, backgroundDispatcher, secureSettings, ) { private val _currentMedia: MutableStateFlow<List<MediaCommonModel>> = MutableStateFlow(mutableListOf()) Loading
packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaCarouselInteractor.kt +32 −2 Original line number Diff line number Diff line Loading @@ -25,6 +25,11 @@ import com.android.internal.logging.InstanceId import com.android.systemui.CoreStartable import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.Edge import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING import com.android.systemui.keyguard.shared.model.KeyguardState.GONE import com.android.systemui.media.controls.data.repository.MediaFilterRepository import com.android.systemui.media.controls.domain.pipeline.MediaDataCombineLatest import com.android.systemui.media.controls.domain.pipeline.MediaDataFilterImpl Loading @@ -37,12 +42,15 @@ import com.android.systemui.media.controls.domain.resume.MediaResumeListener import com.android.systemui.media.remedia.data.repository.MediaPipelineRepository import com.android.systemui.media.remedia.shared.flag.MediaControlsInComposeFlag import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.scene.shared.model.Scenes import java.io.PrintWriter import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn Loading @@ -60,6 +68,8 @@ constructor( private val mediaDataCombineLatest: MediaDataCombineLatest, private val mediaDataFilter: MediaDataFilterImpl, private val mediaPipelineRepository: MediaPipelineRepository, keyguardTransitionInteractor: KeyguardTransitionInteractor, deviceEntryInteractor: DeviceEntryInteractor, ) : MediaDataManager, CoreStartable { /** Are there any media notifications active? */ Loading Loading @@ -91,6 +101,27 @@ constructor( MutableStateFlow(mutableListOf()) } val allowMediaOnLockscreen: StateFlow<Boolean> = mediaPipelineRepository.allowMediaPlayerOnLockscreen internal val isOnLockscreen: Flow<Boolean> = combine( @Suppress("DEPRECATION") keyguardTransitionInteractor.isFinishedIn(Scenes.Gone, GONE), keyguardTransitionInteractor.isInTransition(Edge.create(to = DOZING)), deviceEntryInteractor.isDeviceEntered, ) { isGone, isGoingToDozing, deviceEntered -> if (SceneContainerFlag.isEnabled) { !deviceEntered } else { !isGone || isGoingToDozing } } val isLockedAndHidden = combine(allowMediaOnLockscreen, isOnLockscreen) { allowMedia, onLockscreen -> !allowMedia && onLockscreen } override fun start() { if (!SceneContainerFlag.isEnabled && !MediaControlsInComposeFlag.isEnabled) { return Loading Loading @@ -212,8 +243,7 @@ constructor( val unsupported: Nothing get() = error( "Code path not supported when ${SceneContainerFlag.DESCRIPTION} or " + "media_controls_in_compose is enabled" "Code path not supported when ${SceneContainerFlag.DESCRIPTION} or media_controls_in_compose is enabled" ) } }