Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 646bd519 authored by Beth Thibodeau's avatar Beth Thibodeau Committed by Android (Google) Code Review
Browse files

Merge "[Flexiglass] Hide carousel based on lock screen setting" into main

parents be33599c 8c5da257
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import com.android.systemui.media.controls.ui.controller.MediaCarouselController
import com.android.systemui.media.controls.ui.view.MediaHost
import com.android.systemui.res.R
import com.android.systemui.util.animation.MeasurementInput
import kotlinx.coroutines.ExperimentalCoroutinesApi

object MediaCarousel {
    object Elements {
@@ -46,6 +47,7 @@ object MediaCarousel {
    }
}

@ExperimentalCoroutinesApi
@Composable
fun SceneScope.MediaCarousel(
    isVisible: Boolean,
@@ -54,7 +56,7 @@ fun SceneScope.MediaCarousel(
    carouselController: MediaCarouselController,
    offsetProvider: (() -> IntOffset)? = null,
) {
    if (!isVisible) {
    if (!isVisible || carouselController.isLockedAndHidden()) {
        return
    }

+13 −5
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.Edge
@@ -75,7 +76,6 @@ import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.qs.PageIndicator
import com.android.systemui.res.R
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shared.system.SysUiStatsLog
@@ -103,6 +103,7 @@ import javax.inject.Inject
import javax.inject.Provider
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.distinctUntilChanged
@@ -121,6 +122,7 @@ private val DEBUG = Log.isLoggable(TAG, Log.DEBUG)
 * Class that is responsible for keeping the view carousel up to date. This also handles changes in
 * state and applies them to the media carousel like the expansion.
 */
@ExperimentalCoroutinesApi
@SysUISingleton
class MediaCarouselController
@Inject
@@ -149,7 +151,7 @@ constructor(
    private val secureSettings: SecureSettings,
    private val mediaCarouselViewModel: MediaCarouselViewModel,
    private val mediaViewControllerFactory: Provider<MediaViewController>,
    private val sceneInteractor: SceneInteractor,
    private val deviceEntryInteractor: DeviceEntryInteractor,
) : Dumpable {
    /** The current width of the carousel */
    var currentCarouselWidth: Int = 0
@@ -904,9 +906,15 @@ constructor(

    /** Return true if the carousel should be hidden because lockscreen is currently visible */
    fun isLockedAndHidden(): Boolean {
        val keyguardState = keyguardTransitionInteractor.getFinishedState()
        return !allowMediaPlayerOnLockScreen &&
            KeyguardState.lockscreenVisibleInState(keyguardState)
        val isOnLockscreen =
            if (SceneContainerFlag.isEnabled) {
                !deviceEntryInteractor.isDeviceEntered.value
            } else {
                KeyguardState.lockscreenVisibleInState(
                    keyguardTransitionInteractor.getFinishedState()
                )
            }
        return !allowMediaPlayerOnLockScreen && isOnLockscreen
    }

    private fun reorderAllPlayers(
+105 −5
Original line number Diff line number Diff line
@@ -27,19 +27,24 @@ import android.util.MathUtils.abs
import android.view.View
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.internal.logging.InstanceId
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.SysuiTestCase
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.DisableSceneContainer
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.flags.Flags
import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository
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.SuccessFingerprintAuthenticationStatus
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
@@ -71,14 +76,18 @@ import com.android.systemui.util.settings.FakeSettings
import com.android.systemui.util.settings.GlobalSettings
import com.android.systemui.util.settings.SecureSettings
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import java.util.Locale
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.flow.MutableStateFlow
import kotlinx.coroutines.test.TestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.After
import org.junit.Before
@@ -106,6 +115,7 @@ private val SMARTSPACE_KEY = "smartspace"
private const val PAUSED_LOCAL = "paused local"
private const val PLAYING_LOCAL = "playing local"

@ExperimentalCoroutinesApi
@SmallTest
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@RunWith(AndroidJUnit4::class)
@@ -183,7 +193,7 @@ class MediaCarouselControllerTest : SysuiTestCase() {
                secureSettings = secureSettings,
                mediaCarouselViewModel = kosmos.mediaCarouselViewModel,
                mediaViewControllerFactory = mediaViewControllerFactory,
                sceneInteractor = kosmos.sceneInteractor,
                deviceEntryInteractor = kosmos.deviceEntryInteractor,
            )
        verify(configurationController).addCallback(capture(configListener))
        verify(visualStabilityProvider)
@@ -868,7 +878,6 @@ class MediaCarouselControllerTest : SysuiTestCase() {
    }

    @DisableSceneContainer
    @ExperimentalCoroutinesApi
    @Test
    fun testKeyguardGone_showMediaCarousel() =
        kosmos.testScope.runTest {
@@ -892,7 +901,6 @@ class MediaCarouselControllerTest : SysuiTestCase() {
        }

    @EnableSceneContainer
    @ExperimentalCoroutinesApi
    @Test
    fun testKeyguardGone_showMediaCarousel_scene_container() =
        kosmos.testScope.runTest {
@@ -910,7 +918,6 @@ class MediaCarouselControllerTest : SysuiTestCase() {
            job.cancel()
        }

    @ExperimentalCoroutinesApi
    @Test
    fun keyguardShowing_notAllowedOnLockscreen_updateVisibility() {
        kosmos.testScope.runTest {
@@ -940,7 +947,6 @@ class MediaCarouselControllerTest : SysuiTestCase() {
        }
    }

    @ExperimentalCoroutinesApi
    @Test
    fun keyguardShowing_allowedOnLockscreen_updateVisibility() {
        kosmos.testScope.runTest {
@@ -970,6 +976,74 @@ class MediaCarouselControllerTest : SysuiTestCase() {
        }
    }

    @EnableSceneContainer
    @Test
    fun deviceEntered_mediaAllowed_notLockedAndHidden() {
        kosmos.testScope.runTest {
            val settingsJob =
                mediaCarouselController.listenForLockscreenSettingChanges(
                    kosmos.applicationCoroutineScope
                )
            secureSettings.putBool(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, true)
            setDeviceEntered(true)

            assertEquals(false, mediaCarouselController.isLockedAndHidden())

            settingsJob.cancel()
        }
    }

    @EnableSceneContainer
    @Test
    fun deviceEntered_mediaNotAllowed_notLockedAndHidden() {
        kosmos.testScope.runTest {
            val settingsJob =
                mediaCarouselController.listenForLockscreenSettingChanges(
                    kosmos.applicationCoroutineScope
                )
            secureSettings.putBool(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, false)
            setDeviceEntered(true)

            assertEquals(false, mediaCarouselController.isLockedAndHidden())

            settingsJob.cancel()
        }
    }

    @EnableSceneContainer
    @Test
    fun deviceNotEntered_mediaAllowed_notLockedAndHidden() {
        kosmos.testScope.runTest {
            val settingsJob =
                mediaCarouselController.listenForLockscreenSettingChanges(
                    kosmos.applicationCoroutineScope
                )
            secureSettings.putBool(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, true)
            setDeviceEntered(false)

            assertEquals(false, mediaCarouselController.isLockedAndHidden())

            settingsJob.cancel()
        }
    }

    @EnableSceneContainer
    @Test
    fun deviceNotEntered_mediaNotAllowed_lockedAndHidden() {
        kosmos.testScope.runTest {
            val settingsJob =
                mediaCarouselController.listenForLockscreenSettingChanges(
                    kosmos.applicationCoroutineScope
                )
            secureSettings.putBool(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, false)
            setDeviceEntered(false)

            assertEquals(true, mediaCarouselController.isLockedAndHidden())

            settingsJob.cancel()
        }
    }

    @Test
    fun testInvisibleToUserAndExpanded_playersNotListening() {
        // Add players to carousel.
@@ -1129,4 +1203,30 @@ class MediaCarouselControllerTest : SysuiTestCase() {
            mediaCarouselController.mediaCarouselScrollHandler.visibleMediaIndex
        )
    }

    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()
    }
}