Loading packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt +80 −0 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading Loading @@ -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" Loading packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt +33 −0 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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. */ Loading @@ -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, ) { Loading Loading @@ -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() Loading packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt +1 −1 Original line number Diff line number Diff line Loading @@ -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 } } } } Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +8 −0 Original line number Diff line number Diff line Loading @@ -1225,6 +1225,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()) { Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt +3 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt +80 −0 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading Loading @@ -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" Loading
packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt +33 −0 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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. */ Loading @@ -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, ) { Loading Loading @@ -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() Loading
packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt +1 −1 Original line number Diff line number Diff line Loading @@ -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 } } } } Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +8 −0 Original line number Diff line number Diff line Loading @@ -1225,6 +1225,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()) { Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt +3 −0 Original line number Diff line number Diff line Loading @@ -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