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

Commit 62ced44a authored by Shawn Lee's avatar Shawn Lee
Browse files

[Flexiglass] Base NSSL alpha off bouncer transition, and INVISIBLE when occluded

NSSL should correctly fade out as the bouncer overlay fades in, and become View.INVISIBLE once the bouncer is fully faded in. This should also fix inline reply functionality.

Bug: 398890669
Bug: 390503464
Test: manually verified NSSL alpha change during Shade -> Bouncer transition
Test: manually verified inline reply works
Test: new unit test forthcoming
Flag: com.android.systemui.scene_container
Change-Id: Ice93016bce30abce5497b07412cacc039cfd7d1c
parent ea66d64c
Loading
Loading
Loading
Loading
+80 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.content.testableContext
import android.provider.Settings.Global.ONE_HANDED_KEYGUARD_SIDE
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.internal.logging.uiEventLoggerFake
import com.android.systemui.SysuiTestCase
import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
@@ -39,13 +40,22 @@ import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.flags.Flags.FULL_SCREEN_USER_SWITCHER
import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFaceAuthRepository
import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.runCurrent
import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testScope
import com.android.systemui.power.data.repository.fakePowerRepository
import com.android.systemui.res.R
import com.android.systemui.scene.data.repository.sceneContainerRepository
import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.transitionState
import com.android.systemui.testKosmos
import com.android.systemui.util.settings.fakeGlobalSettings
import com.google.common.truth.Truth.assertThat
import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
@@ -368,6 +378,76 @@ class BouncerInteractorTest : SysuiTestCase() {
            testableResources.removeOverride(R.bool.can_use_one_handed_bouncer)
        }

    @Test
    fun bouncerExpansion_lockscreenToBouncer() =
        kosmos.runTest {
            val bouncerExpansion by collectLastValue(underTest.bouncerExpansion)

            val progress = MutableStateFlow(0f)
            kosmos.sceneContainerRepository.setTransitionState(transitionState)
            transitionState.value =
                ObservableTransitionState.Transition.showOverlay(
                    overlay = Overlays.Bouncer,
                    fromScene = Scenes.Lockscreen,
                    currentOverlays = flowOf(emptySet()),
                    progress = progress,
                    isInitiatedByUserInput = false,
                    isUserInputOngoing = flowOf(false),
                )

            assertThat(bouncerExpansion).isEqualTo(0f)

            progress.value = 1f
            assertThat(bouncerExpansion).isEqualTo(1f)
        }

    @Test
    fun bouncerExpansion_BouncerToLockscreen() =
        kosmos.runTest {
            val bouncerExpansion by collectLastValue(underTest.bouncerExpansion)

            val progress = MutableStateFlow(0f)
            kosmos.sceneContainerRepository.setTransitionState(transitionState)
            transitionState.value =
                ObservableTransitionState.Transition.hideOverlay(
                    overlay = Overlays.Bouncer,
                    toScene = Scenes.Lockscreen,
                    currentOverlays = flowOf(emptySet()),
                    progress = progress,
                    isInitiatedByUserInput = false,
                    isUserInputOngoing = flowOf(false),
                )

            assertThat(bouncerExpansion).isEqualTo(1f)

            progress.value = 1f
            assertThat(bouncerExpansion).isEqualTo(0f)
        }

    @Test
    fun bouncerExpansion_shadeToLockscreenUnderBouncer() =
        kosmos.runTest {
            val bouncerExpansion by collectLastValue(underTest.bouncerExpansion)

            val progress = MutableStateFlow(0f)
            kosmos.sceneContainerRepository.setTransitionState(transitionState)
            transitionState.value =
                ObservableTransitionState.Transition(
                    fromScene = Scenes.Shade,
                    toScene = Scenes.Lockscreen,
                    currentScene = flowOf(Scenes.Lockscreen),
                    progress = progress,
                    isInitiatedByUserInput = false,
                    isUserInputOngoing = flowOf(false),
                    currentOverlays = setOf(Overlays.Bouncer),
                )

            assertThat(bouncerExpansion).isEqualTo(1f)

            progress.value = 1f
            assertThat(bouncerExpansion).isEqualTo(1f)
        }

    companion object {
        private const val MESSAGE_ENTER_YOUR_PIN = "Enter your PIN"
        private const val MESSAGE_ENTER_YOUR_PASSWORD = "Enter your password"
+33 −0
Original line number Diff line number Diff line
@@ -17,7 +17,9 @@
package com.android.systemui.bouncer.domain.interactor

import android.app.StatusBarManager.SESSION_KEYGUARD
import com.android.app.tracing.FlowTracing.traceAsCounter
import com.android.app.tracing.coroutines.asyncTraced as async
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.compose.animation.scene.SceneKey
import com.android.internal.logging.UiEventLogger
import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
@@ -38,9 +40,12 @@ import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInt
import com.android.systemui.log.SessionTracker
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.scene.domain.interactor.SceneBackInteractor
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
@@ -49,7 +54,9 @@ import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map

/** Encapsulates business logic and application state accessing use-cases. */
@@ -65,6 +72,7 @@ constructor(
    private val powerInteractor: PowerInteractor,
    private val uiEventLogger: UiEventLogger,
    private val sessionTracker: SessionTracker,
    sceneInteractor: SceneInteractor,
    sceneBackInteractor: SceneBackInteractor,
    @ShadeDisplayAware private val configurationInteractor: ConfigurationInteractor,
) {
@@ -149,6 +157,31 @@ constructor(
    val dismissDestination: Flow<SceneKey> =
        sceneBackInteractor.backScene.map { it ?: Scenes.Lockscreen }

    /** The amount [0-1] that the Bouncer Overlay has been transitioned to. */
    val bouncerExpansion: Flow<Float> =
        if (SceneContainerFlag.isEnabled) {
                sceneInteractor.transitionState.flatMapLatestConflated { state ->
                    when (state) {
                        is ObservableTransitionState.Idle ->
                            flowOf(if (Overlays.Bouncer in state.currentOverlays) 1f else 0f)
                        is ObservableTransitionState.Transition ->
                            if (state.toContent == Overlays.Bouncer) {
                                state.progress
                            } else if (state.fromContent == Overlays.Bouncer) {
                                state.progress.map { progress -> 1 - progress }
                            } else {
                                state.currentOverlays().map {
                                    if (Overlays.Bouncer in it) 1f else 0f
                                }
                            }
                    }
                }
            } else {
                flowOf()
            }
            .distinctUntilChanged()
            .traceAsCounter("bouncer_expansion") { (it * 100f).toInt() }

    /** Notifies that the user has places down a pointer, not necessarily dragging just yet. */
    fun onDown() {
        falsingInteractor.avoidGesture()
+1 −1
Original line number Diff line number Diff line
@@ -334,7 +334,7 @@ constructor(
                        } else if (state.fromContent == overlay) {
                            state.progress.map { progress -> 1 - progress }
                        } else {
                            flowOf(0f)
                            state.currentOverlays().map { if (overlay in it) 1f else 0f }
                        }
                }
            }
+8 −0
Original line number Diff line number Diff line
@@ -1210,6 +1210,14 @@ public class NotificationStackScrollLayout
        mController.setMaxAlphaFromView(alpha);
    }

    @Override
    public void setOccluded(boolean isOccluded) {
        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) {
            return;
        }
        this.setVisibility(isOccluded ? View.INVISIBLE : View.VISIBLE);
    }

    @Override
    public void setScrollState(@NonNull ShadeScrollState scrollState) {
        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) {
+3 −0
Original line number Diff line number Diff line
@@ -49,6 +49,9 @@ interface NotificationScrollView {
    /** Max alpha for this view */
    fun setMaxAlpha(alpha: Float)

    /** Set whether this view is occluded by something else. */
    fun setOccluded(isOccluded: Boolean)

    /** Sets a clipping shape, which defines the drawable area of this view. */
    fun setClippingShape(shape: ShadeScrimShape?)

Loading